home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
AmigActive 10
/
AACD 10.iso
/
AACD
/
Online
/
cnetdevice
/
src
/
cnetdevice.asm
< prev
next >
Wrap
Assembly Source File
|
2000-05-25
|
122KB
|
4,469 lines
;---------------------------------------------------------------------------
; PCMCIA ethernet card driver for A600/A1200
;---------------------------------------------------------------------------
;
; HISTORY:
;
; 10-4-97 v0.1 - Created by Bruce Abbott (bhabbott@inhb.co.nz)
; *** First Aminet Release ***
;
; 29-4-97 v0.2 - Implemented CMD_ONLINE/OFFLINE/FLUSH (for Miami).
;
; - Enabled interrupts during RemoteWrite (no more serial
; port overruns!).
;
; 6-5-97 v0.3 - Added a flag so that we won't try to ReleaseCard()
; unless there was a successful OwnCard()!
;
; 17-5-97 v0.4 - CMD_CONFIGINTERFACE now overrides the default hardware
; address (for Miami).
;
; - Device now goes offline if the PCMCIA card is removed.
;
; - CMD_ONEVENT implemented.
;
; - Loosened hardware address verification to accept the
; Accton EN2216.
;
; - Unrolled loops to improve data transfer speed. Now
; about 20% faster on an unexpanded A600.
;
; - Hack to fix problem with missed interrupts. Now we
; clear the Gayle interrupt bits instead of letting
; card.resource do it for us.
;
; *** Second Aminet Release ***
;
; 29-7-97 v0.5 - Accepts 802.3 packets (untested).
;
; - Sets BROADCAST bit in io_flags when appropriate.
;
; - Now examines PCMCIA attribute memory to determine
; value to write into Card Configuration Register.
;
; - If attribute memory not found, tries to open the file
; "s:cnetdev.config" to get Card Configuration Register
; offset, Configuration ID, and ROM Station Address.
;
; *** Third Aminet Release ***
;
;22-12-97 v0.6 - I/O addressing now supports 64KByte range (was 1KB).
;
; - Tighter data transfer loops, slightly faster on '030.
;
; - Accepts all Card Configuration Register address sizes.
;
; - Removed cnet.config stuff (replaced with hardware mod).
;
; - Now cards are hot-swappable.
;
; - Un-supported commands now return S2ERR_NOT_SUPPORTED.
;
; *** 4th Aminet Release ***
;
;21-4-98 v0.7 - fixed harmless bug in init_nic - remote DMA timeout test
; could not fail!
;
; - Now remembers copytobuf/copyfrombuf tags for each opener.
; Allows simultaneous use of eg. AmiTCP and Envoy.
;
; - OnEvent types ONLINE and OFFLINE now return immediately
; if the device is already in the wanted state.
;
; *** 5th Aminet Release ***
;
;17-12-98 v0.8 - fixed bug in OnEvent: was using wrong register to test
; ONLINE flag.
;
; 1-6-99 v0.9 - Added support for multicasting, statistics, orphan packets,
; exclusive and promiscuous modes.
;
; *** 6th Aminet Release ***
;
; 5-7-99 v1.0 - Fixed bug in readpacket: MCAST flag was also set when packet
; was BCAST.
;
; *** 7th Aminet Release ***
;
; 7-7-99 v1.1 - Fixed bug: delmulticast always failed due to bad testing
; for multicast address match.
;
; - Fixed bug: readpacket was getting incorrect src and dst
; addresses (A4 was pointing to prhdr instead of etherhdr).
;
; - Included put_multi in init_nic (need to reload multicast
; bits if card is removed and re-inserted)
;
; - Added 4 to rx ios2_datalength in raw mode. Shapeshifter
; seems to need this (why?)
;
; *** 8th Aminet release ***
;
;7-5-00 v1.2b1 - Since there has been almost ten months without an update,
; I, Harry Sintonen <sintonen@iki.fi>, decided to have a go.
;
; - Reformatted this source code: Now registers are always in
; lowercase, for better readability.
;
; - Added MN_LENGTH check for OpenDevice() (S2R3 and NSD require
; this).
;
; - Fixed a bug: If TAG_IGNORE, TAG_MORE or TAG_SKIP were used
; in the IOSana2Req's taglist Open_Unit got really confused,
; throwing enforcer hits, and in a worst case, crashing the
; machine. Now uses utility.library GetTagData().
;
; - Optimized dbf loops to subq + branch for better 020+
; performance. Made several other miscallenous optimizations
; thruout the code.
;
; - More bugs fixed: DoEvent examined dd_eventlist before
; Disable(). devcmd_addmulticast and devcmd_delmulticast
; didn't lock the list, devcmd_delmulticast called Enable()
; without Disable() when no multicast was found. Protected
; dd_multicasts list with semaphore. dd_bufmanlist was
; accessed without list arbitration, added Disable()/Enable()
; pair when needed.
;
; - Added support for S2_PacketFilter tag. Speedup: replaced
; several list related calls with macros.
;
; - Rewrote CMD_READ handling: Added proper Multiple Protocol
; Stack Support, it was really broken before. Basically this
; means that each opener gets all the packets necessary. If a
; packet comes in that fills a request for more than one
; opener of the device, *all* of them will get a copy of the
; packet. Of course each caller can ask RAW or non-RAW version
; of the packet. cnet.device fully comply to S2R2 now!
;
; - Since complies to S2R2, added NewStyleDevice (NSD) support.
; Also added S2R3 S2_DMACopyFromBuff32 tag support, however
; this feature is currently disabled. ***
; S2_DMACopyToBuff32 would only pay off if: 1) there is only
; one caller for this packet, and 2) there is no packet filter
; for this caller.
;
; - More speedups: Replaced exec Disable() and Enable() calls
; with macros. Yet more list related calls replaced with
; macros.
;
; - Yet more bugs fixed: CMD_FLUSH didn't abort S2_READORPHANs.
; CMD_OFFLINE didn't abort pending CMD_READs, S2_READORPHANs
; and CMD_WRITEs. CMD_READ and S2_READORPHAN didn't check for
; card being online. S2_ONEVENT didn't check if it knows the
; event condition(s) specified, instead requests for unknown
; event(s) would never have got returned. Also S2_ONEVENT
; returned the ioreq even if it was queued. S2_CONFIGINTERFACE
; worked more than once, it *must* only work once.
; OpenDevice() incorrectly required S2_CopyFromBuff and
; S2_CopyToBuff tags to be present.
;
; - Yet more speedups: DoEvent uses global cached device
; pointer.
;
; - init_card and init_nic fire S2EVENT_ERROR|S2EVENT_HARDWARE
; event if something goes wrong. Trying to send too big of a
; packet trigger S2EVENT_TX. If packet gets dropped during
; receive S2EVENT_ERROR|S2EVENT_RX event is triggered. If
; copyfrombuf while transmitting fails S2EVENT_TX|S2EVENT_BUFF
; event is triggered, and similarily if copytobuf while
; receiving fails S2EVENT_RX|S2EVENT_BUFF event is triggered.
;
; - Extensively debugged for 18+6 hours to make 1st early beta
; possible...
;
; - Currently at least following should work: CMD_READ,
; CMD_WRITE, CMD_FLUSH, S2_DEVICEQUERY, S2_GETSTATIONADDRESS,
; S2_CONFIGINTERFACE, S2_ADDMULTICASTADDRESS,
; S2_DELMULTICASTADDRESS, S2_MULTICAST, S2_BROADCAST,
; S2_TRACKTYPE, S2_UNTRACKTYPE, S2_GETTYPESTATS,
; S2_GETSPECIALSTATS, S2_GETGLOBALSTATS, S2_ONEVENT,
; S2_READORPHAN, S2_ONLINE, S2_OFFLINE and NSCMD_DEVICEQUERY.
;
; - Tested with sanamon, sanautil, miamidx and genesis.
;
; *** internal 1.2beta1 release ***
;
;9-5-00 v1.2b2 - initRoutine trashed a6 by leaving execbase in it, but since
; it *is* execbase originally it was harmless. Silly. :)
;
; - Misc minor changes here and there.
;
; - Added device expunge. esp. cool for debugging, no more those
; damn annoying reboots. Also someone might want to quit
; protocol stack, avail flush, and use some other card without
; the need to reboot. Now DDF_CONFIGURED is reset only on
; device flush, this means that pulling the card out doesn't
; cut the connection anymore, and you can continue by plugging
; the card back in. v1.2b1 didn't allow this hot swapping
; trick, but v1.1 did.
;
; - Bugfixes: initRoutine crashed if utility.library v36 failed
; to open. Partially successful OpenDevice ate some resources,
; now it should be able to back out in all cases. S2_OFFLINE
; should, I quote: "Aborts all pending reads and writes with
; ios2_Error set to S2ERR_OUTOFSERVICE.". However this makes
; MiamiDx die a horrible death. Took me 10 hours to find why.
; Damn it! Disabled IO aborting and now it works. D'oh!
;
; - Speedup: Implemented turbo RemoteRead & RemoteWrite loops,
; they use longword access to 16bit register. Don't worry,
; this works, but honestly I have no clue why. Enabled DMA for
; both regular and raw CMD_WRITEs. At least MiamiDx support
; S2_DMACopyFromBuff32. Moving 30mb mpg between my amiga and
; laptop result about 450kb/s upload and 500kb/s download
; speed. v1.1 and the same environment gave about 420kb/s
; upload and 450kb/s download speed.
; (ftp client AmFTP 1.92, ftpd Version 6.2/OpenBSD/Linux-0.10)
;
; - Made Makefile generate 68000 version of the device. No real
; differences yet tho. this version is untested!
;
; *** internal 1.2beta2 release ***
;
;16-5-00 v1.2b3 Got a report that v1.2b2 is actually slower than v1.2b1.
; Well I wrote a simple AmigaE program that I can use to
; benchmark cnet.device CMD_WRITE. Turned out that turboio
; transfer ~679kb/s and non-turboio 697kb/s without DMA
; transfer, in DMA mode the same figures are 694kb/s vs. 713
; kb/s. Oh dear, this is it, I disabled turboio. :) Thanks go
; to Tundrah for the tip. BTW: it seems we're finally getting
; there, he get ~770kb/s real life transfer speed using FTP
; (Apollo ethernet, 060 @ 66). Not bad. Btw benchmarking
; CMD_READ is a bit problematic for me as I don't have really
; state of the art machine on the other end and it can't feed
; the card at the full speed. However Tundrah also told me
; that for some reason MiamiDx is slow compared to Genesis. I
; did some tests with both MiamiDx and Genesis, used ftp
; client AmFTP 1.92 and ftpd Version 6.2/OpenBSD/Linux-0.10.
; Download speed with Genesis was 720kb/s and with MiamiDx 530
; kb/s. Genesis is %33 faster. For fucks sake wtf Miami is
; doing? busyloops or what? :) This probably means that
; someone should make a MNI driver. Any volunteers?
;
; - Forget that mumbo jumbo about MMU speedup hack that was
; mentioned in v1.2b2. 1) no real speedup due the way I/O
; is accessed. 2) many amiga 060 turbo cards don't have
; special hardware to handle writebuffer burst write ->
; undefined behavior. (Thanks to Ralph Schmidt for helping me
; understand this)
;
; - Bugfix: AbortIO failed to abort S2_MULTICAST or S2_BROADCAST
; requests.
;
; *** internal 1.2beta3 release ***
;
;19-5-00 v1.2b4 Misc little changes here and there, nothing major.
;
; - Speedup: inlined optimized version of RemoteRead for reading
; prhdr and etherheader. Joined rx_header and rxbuffer. As a
; result code simplified and sped up. For me the speedup is
; +2kb/s. Inlined couple of other subroutines that are called
; only once.
;
; - Speedup: Got a report from darza saying that turboio indeed
; is faster with `cnet' card. He got 720kb/s with v1.1,
; v1.2beta1 and v1.2beta3, but 750kb/s with v1.2beta2. Eek! :)
; Tweaked makefile to compile separate turboio version. It is
; up to user to find out which one is faster. Currently non-
; turboio ftp download peaked 754kb/s. Turboio version peaked
; 771kb/s. Could be that turboio is faster on 060 @ 50 systems
; and non-turboio on overclocked 060 systems. Why? Maybe some
; I/O timing issues... No idea really, just guessing. Need to
; ask Tundrah to do more benchmarking. :)
;
; - Improvements: added support for S2_ADDMULTICASTADDRESSES and
; S2_DELMULTICASTADDRESSES (Multicast address range extensions
; to SANA-II Rev 3). Implemented S2_ADDMULTICASTADDRESS and
; S2_DELMULTICASTADDRESS using range of addr -> addr. Added
; CPU type to version string. Added 68020 CPU check to 68020+
; version. Device IDString no longer has '$VER: ' included.
; Now uses CARDF_POSTSTATUS instead of a hack if card.resource
; V39+ is available (note that KS 3.0 has *V37* card.resource,
; and KS 3.1 has V40). Added workaround for Genesis bug, it
; calls S2_ONLINE before S2_CONFIGINTERFACE.
;
; *** internal 1.2beta4 release ***
;
;25-5-00 v1.2 - Made compile with standard os-includes.
;
; *** 9th Aminet release ***
;
; todo: Do some more 020+ optimizations (the ones that really pay off!)
; Make it use memory pool (not really worth it I think)
; CopyTo/CopyFrom 16/32 support? (ADCD_2.1:DevInfo/Networking/SANA2Revision3)
; Add support for more cards? (not in this device in this life, unless easily implemented)
;
; configured from makefile
;debug = 1
;verbose=1
;turboio = 1
; misc flags
;realdisable=1 ; use exec functions or macros ?
include exec/types.i
include exec/nodes.i
include exec/lists.i
include exec/libraries.i
include exec/errors.i
include exec/initializers.i
include exec/resident.i
include exec/memory.i
include exec/interrupts.i
include exec/semaphores.i
include exec/ports.i
include exec/io.i
include exec/devices.i
include exec/tasks.i
include devices/timer.i
IFND realdisable
include exec/ables.i
ENDC
include funcdef.i
include exec/exec_lib.i
IFND _LVOGetSysTime
_LVOGetSysTime = -66 ; timer lib function
ENDC
IFND _LVOGetTagData
_LVOGetTagData = -36 ; utility lib function
ENDC
include pcmcia.i ; card.resource etc.
include sanaii.i ; the essential network stuff
include cnet.i ; hardware specific stuff
VERSION = 1
REVISION = 2
VERSTR macro
dc.b "1.2 (25.5.2000)"
endm
; 1uS delay before nic register access
; May not be required with slower CPUs.
delay MACRO
; tst.b $bfe001 ; at least 1uS, even on fast machines
ENDM
MYDISABLE MACRO
IFD realdisable
jsr _LVODisable(a6)
ELSE
MOVE.W #$4000,$DFF09A
ADDQ.B #1,IDNestCnt(A6)
ENDC
ENDM
MYENABLE MACRO
IFD realdisable
jsr _LVOEnable(a6)
ELSE
SUBQ.B #1,IDNestCnt(A6)
BGE.S .MYENABLE\@
MOVE.W #$C000,$DFF09A
.MYENABLE\@:
ENDC
ENDM
MYREMHEAD MACRO
MOVE.L (A0),A1
MOVE.L (A1),D0
BEQ.S .MYREMHEAD\@
MOVE.L D0,(A0)
EXG.L D0,A1
MOVE.L A0,LN_PRED(A1)
.MYREMHEAD\@
ENDM
;===========================================================================
section 0,CODE
;-----------------------------------------------------------------------
; The first executable location. This should return an error
; in case someone tried to run you as a program (instead of
; loading you as a device).
start_exe:
moveq #-1,d0 ; it's a device, not an application!
rts
;-----------------------------------------------------------------------
; A romtag structure. After your driver is brought in from disk, the
; disk image will be scanned for this structure to discover magic constants
; about you (such as where to start running you from...).
;-----------------------------------------------------------------------
romtag:
dc.w RTC_MATCHWORD ; RT_MATCHWORD
dc.l romtag ; RT_MATCHTAG
dc.l Endcode ; RT_ENDSKIP
dc.b RTF_AUTOINIT ; RT_FLAGS
dc.b VERSION ; RT_VERSION
dc.b NT_DEVICE ; RT_TYPE
dc.b 0 ; RT_PRI
dc.l DeviceName ; RT_NAME
dc.l IDString ; RT_IDSTRING
dc.l Init ; RT_INIT
Init:
dc.l dd_extsize ; data space size
dc.l funcTable ; pointer to function initializers
dc.l dataTable ; pointer to data initializers
dc.l initRoutine ; routine to run at startup
funcTable:
dc.w -1
dc.w Open_Device-funcTable
dc.w Close_Device-funcTable
dc.w Expunge_Device-funcTable
dc.w _Null-funcTable
dc.w _DevBeginIO-funcTable
dc.w _DevAbortIO-funcTable
dc.w -1
dataTable:
INITBYTE LN_TYPE,NT_DEVICE
INITLONG LN_NAME,DeviceName
INITBYTE LIB_FLAGS,LIBF_SUMUSED|LIBF_CHANGED
INITWORD LIB_VERSION,VERSION
INITWORD LIB_REVISION,REVISION
INITLONG LIB_IDSTRING,idString
dc.w 0
include debugs.i
;=======================================================
; initRoutine
;=======================================================
;
; This routine gets called after the device has been allocated.
; The device pointer is in d0. The AmigaDOS segment list is in a0.
; If it returns the device pointer, then the device will be linked
; into the device list. If it returns NULL, then the device will
; be unloaded. This call is single-threaded.
;
; input: a0 = seglist
; d0 = device
; a6 = execbase
;
initRoutine:
movem.l d1-d7/a0-a5,-(sp)
move.l d0,a5
move.l a0,a4
ifge __CPU-68020
btst #AFB_68020,AttnFlags+1(a6)
beq.s .err
endc
lea utilityName(pc),a1
moveq #36,d0
jsr _LVOOpenLibrary(a6)
move.l d0,utility_base ; store utilitybase
beq.s .err ; oops failed, return failure
move.l a4,dd_SegList(a5) ; seglist for expunge
move.l a6,exec_base ; local copy of execbase
move.l a5,me_myself ; for speedup
move.l a5,d0
.pop:
movem.l (sp)+,d1-d7/a0-a5
rts
.err:
moveq #0,d0
bra.s .pop
_Null:
moveq #0,d0
rts
;----------------------------------------------------------------------
;
; Here begins the system interface commands. When the user calls
; OpenDevice/CloseDevice/RemDevice, this eventually gets translated
; into a call to the following routines (Open_Device/Close_Device/
; Expunge_Device). Exec has already put our device pointer in a6 for
; us.
;=================================================================
; Open Device
;=================================================================
;
; error = Open_Device(device, ioreq, unitnum, flags)
; d0 a6 a1 d0 d1
;
; Open sets the IO_ERROR field on an error. If it was successfull,
; we should also set up the IO_UNIT and LN_TYPE fields. Exec takes
; care of setting up IO_DEVICE.
;
Open_Device:
;
;** Subtle point: any AllocMem() call can cause a call to this device's
;** expunge vector. If LIB_OPENCNT is zero, the device might get expunged.
;
addq.w #1,lib_opencnt(a6) ; Fake an opener for duration of call <|>
bug <10,"cnet: OpenDevice(ioreq $%lx, unit %ld, flags $%02lx)",10>,a1,d0,d1
ifgt 0
ifd debug
ifd verbose
move.l #100000,d0
.wait:
tst.b $bfe001
subq.l #1,d0
bne.s .wait
endc
endc
endc
movem.l d2-d4/a2-a4/a6,-(sp)
move.l a6,a3 ; a3 = device
move.l a1,a4 ; a4 = ioreq
move.l d0,d4 ; d4 = unit
cmp.w #IOS2_SIZE,mn_length(a4) ; reject invalid requests
blt .badcaller
btst #DDB_MINE,dd_flags2(a3)
bne .isexclusive
btst #SANA2OPB_MINE,d1 ; want exclusive mode ?
beq.s .init
cmp.w #1,lib_opencnt(a3) ; must not be any other openers
bne .isnonexcl
bset #DDB_MINE,dd_flags2(a3) ; set exclusive mode
btst #SANA2OPB_PROM,d1
beq.s .init
bset #DDB_PROM,dd_flags2(a3) ; set promiscuous mode
.init:
move.l a3,a1
bsr init_device ; init device data structures
move.l a3,a0
move.l a4,a1
move.l d4,d0
bsr Open_Unit ; open unit
move.l d0,io_unit(a4)
beq .openerr
btst #DDB_NICUP,dd_flags(a3) ; nic already initialised ?
bne.s .nickdone
move.l a3,a1
bsr init_card ; init PCMCIA card
tst.l d0
bne.s .error
move.l a3,a1
bsr init_nic ; set up nic
tst.l d0
bne.s .error
.nickdone:
btst #DDB_OFFLINE,dd_flags(a3) ; previously put offline ?
bne.s .opened
bset #DDB_ONLINE,dd_flags(a3) ; ready to accept packets
.opened:
clr.b io_error(a4) ; IMPORTANT: Mark IORequest as "complete"
move.b #NT_REPLYMSG,ln_type(a4)
addq.w #1,lib_OpenCnt(a3) ; opened successfully
bclr #LIBB_DELEXP,lib_flags(a3) ; prevent delayed expunges
moveq #0,d0
bug <"cnet: OpenDevice OK",10,10>
.done:
movem.l (sp)+,d2-d4/a2-a4/a6
subq.w #1,lib_opencnt(a6) ; ** End of expunge protection <|>
rts
.badcaller
bug <"cnet: OpenDevice invalid MN_LENGTH!",10>
bra.s .openerr
.isexclusive:
bug <"cnet: device already in use exclusively!",10>
bra.s .openerr
.isnonexcl:
bug <"cnet: device already in use non-exclusively!",10>
bra.s .openerr
.notask:
; task creation failed, cleanup; kill the nic!
move.l a3,a1
bsr kill_nic
.error:
move.l dd_cardres(a3),d0 ; did card.resource open ?
beq.s .nocard
move.l d0,a6
bclr #DDB_OWNED,dd_flags(a3) ; did we own card ?
beq.s .nocard
lea dd_cardhandle(a3),a1
moveq #CARDF_REMOVEHANDLE,d0
jsr _LVOReleaseCard(a6) ; release card
.nocard:
move.l ios2_buffermanagement(a4),d0
beq.s .nobufman ; got a buffermanagement pointer ?
clr.l ios2_buffermanagement(a4)
move.l exec_base(pc),a6
move.l d0,a1
move.l d0,a2
bug <"cnet: OpenDevice remove bufman at $%lx",10>,a1
MYDISABLE ; lock access to list
REMOVE ; remove bufman struct from list
MYENABLE ; release lock on list
move.l a2,a1
moveq #bufman_sizeof,d0
jsr _LVOFreeMem(a6) ; discard buffer management struct
.nobufman:
.openerr:
moveq #IOERR_OPENFAIL,d0 ; error, opendevice failed!
move.b d0,io_error(a4)
move.l d0,io_unit(a4)
move.l d0,io_device(a4) ; IMPORTANT: trash IO_DEVICE on open failure
bug <"cnet: OpenDevice failed!",10,10>
bra.s .done
;===============================================================
; unit=Open Unit(device, ioreq, unitnum)
; d0 a0 a1 d0
;===============================================================
;
; Get the caller's buffer copy callback vectors
;
Open_Unit:
bug <"cnet: Open_Unit(ioreq $%08lx) taglist: $%08lx",10>,a1,ios2_buffermanagement(a1)
movem.l d2-d6/a2-a5,-(sp)
move.l a0,a4 ; a4 = device
move.l a1,a5 ; a5 = ioreq
tst.l d0 ; only unit 0 is supported
bne .error
; If null taglist is supplied we don't fail!
move.l ios2_buffermanagement(a5),d0 ; tag list supplied?
beq .ok
moveq #0,d2 ; d2 = tags found
move.l d0,a2 ; a2 = tag list
; Note: I don't complain if I can't find pointers to the callback
; routines. This is because there are some programs that may need to
; open the device, but will never use any device commands that
; require the callbacks. Instead I check on CMD_READ, CMD_READORPHAN
; and CMD_WRITE for missing routines.
move.l exec_base(pc),a6
moveq #bufman_sizeof,d0 ; allocate memory for bufman vectors
moveq #MEMF_PUBLIC,d1
jsr _LVOAllocMem(a6)
move.l d0,ios2_buffermanagement(a5) ; return bufman node
beq .error
move.l d0,a3
move.l utility_base(pc),a6
; get copyfrom functions:
move.l #S2_COPYFROMBUFF,d0
moveq #0,d1
move.l a2,a0
jsr _LVOGetTagData(a6)
move.l d0,bufman_copyfrombuf(a3)
; This is new SANA-II V3 Addition
move.l #S2_DMACopyFromBuff32,d0
moveq #0,d1
move.l a2,a0
jsr _LVOGetTagData(a6)
move.l d0,bufman_dmacopyfrombuf32(a3)
bug <"cnet: S2_DMACopyFromBuff32 = $%08lx",10>,d0
; get copyto functions:
move.l #S2_COPYTOBUFF,d0
moveq #0,d1
move.l a2,a0
jsr _LVOGetTagData(a6)
move.l d0,bufman_copytobuf(a3)
; This is new for SANA-II V3 Addition
move.l #S2_DMACopyToBuff32,d0
moveq #0,d1
move.l a2,a0
jsr _LVOGetTagData(a6)
move.l d0,bufman_dmacopytobuf32(a3)
bug <"cnet: S2_DMACopyToBuff32 = $%08lx",10>,d0
; And this is new SANA-II V2 Addition
move.l #S2_PACKETFILTER,d0
moveq #0,d1
move.l a2,a0
jsr _LVOGetTagData(a6)
move.l d0,bufman_packetfilter(a3) ; if null everything get thru
ifd debug
bug <"cnet: S2_PacketFilter = $%08lx",10>,d0
ifd verbose
tst.l d0
beq.s .v1
move.l d0,a0
bug <"cnet: PacketFilter h_Entry = $%08lx h_SubEntry = $%08lx h_Data = $%08lx",10>,8(a0),12(a0),16(a0)
.v1:
move.l #S2_COPYFROMBUFF16,d0
moveq #0,d1
move.l a2,a0
jsr _LVOGetTagData(a6)
bug <"cnet: S2_CopyFromBuff16 = $%08lx",10>,d0
move.l #S2_COPYTOBUFF16,d0
moveq #0,d1
move.l a2,a0
jsr _LVOGetTagData(a6)
bug <"cnet: S2_CopyToBuff16 = $%08lx",10>,d0
move.l #S2_COPYFROMBUFF32,d0
moveq #0,d1
move.l a2,a0
jsr _LVOGetTagData(a6)
bug <"cnet: S2_CopyFromBuff32 = $%08lx",10>,d0
move.l #S2_COPYTOBUFF32,d0
moveq #0,d1
move.l a2,a0
jsr _LVOGetTagData(a6)
bug <"cnet: S2_CopyToBuff32 = $%08lx",10>,d0
endc
endc
move.l exec_base(pc),a6
; Init the list for CMD_READ requests
lea bufman_rxqueue(a3),a0
NEWLIST a0
bug <"cnet: addbufman at $%lx",10>,a3
lea dd_bufmanlist(a4),a0
move.l a3,a1
MYDISABLE ; lock access to list
ADDHEAD ; add to buffer management list
MYENABLE ; release lock on list
bra.s .ok
.error:
moveq #0,d0 ; return error
bra.s .done
.ok:
moveq #1,d0 ; return OK
.done:
movem.l (sp)+,d2-d6/a2-a5
rts
;============================================================
; Close Device
;============================================================
;
; Seglist = CloseDevice(ioreq, device)
; d0 a1 a6
;
;
; There are two different things that might be returned from the Close
; routine. If the device wishes to be unloaded, then Close must return
; the segment list (as given to Init). Otherwise close MUST return NULL.
;
;
Close_Device:
bug <10,"cnet: CloseDevice(ioreq $%08lx)",10>,a1
ifgt 0
ifd debug
ifd verbose
move.l #100000,d0
.wait:
tst.b $bfe001
subq.l #1,d0
bne.s .wait
endc
endc
endc
movem.l a2-a4/a6,-(sp)
move.l a1,a3 ; a3 = ioreq
move.l a6,a4 ; a4 = device
moveq #0,d0 ; default: no unload
tst.w lib_OpenCnt(a4)
beq .done ; invalid state!
move.l exec_base(pc),a6
moveq #-1,d0
move.l d0,io_unit(a3) ; We're closed...
move.l d0,io_device(a3) ; customers not welcome at this IORequest!!
move.l ios2_buffermanagement(a3),d0
beq.s .nobufman ; got a buffermanagement pointer ?
clr.l ios2_buffermanagement(a3)
move.l d0,a1
move.l d0,a2
bug <"cnet: remove bufman at $%lx",10>,a1
MYDISABLE ; lock access to list
REMOVE ; remove bufman struct from list
MYENABLE ; release lock on list
move.l a2,a1
moveq #bufman_sizeof,d0
jsr _LVOFreeMem(a6) ; discard buffer management struct
.nobufman:
moveq #0,d0 ; default: no unload
subq.w #1,lib_OpenCnt(a4) ; one less opener
bne.s .done ; still open ?
bug <"cnet: devclosedown",10>
; close down the devive
move.l a4,a1
; a6 = execbase
bsr devclosedown
moveq #0,d0 ; default: no unload
btst #LIBB_DELEXP,lib_flags(a4)
beq.s .done ; delayed expunge pending ?
; do the expunge
bug <"cnet: LIBF_DELEXP calling Expunge!",10>
move.l a4,a6
bsr.s Expunge_Device
.done:
movem.l (sp)+,a2-a4/a6
bug <"cnet: CloseDevice return: $%08lx",10,10>,d0
rts ; MUST return either zero or the SegList!!!
;============================================================
; Expunge Device
;============================================================
;
; Seglist = ExpungeDevice(device)
; d0 a6
;
; Expunge is called by the memory allocator when the system is low on
; memory (or by us from the CloseDevice above!).
;
; There are two different things that might be returned from the Expunge
; routine. If the device is no longer open then Expunge may return the
; segment list (as given to Init). Otherwise Expunge may set the delayed
; expunge flag and return NULL.
;
; One other important note: because Expunge is called from the memory
; allocator, it may NEVER Wait() or otherwise take long time to complete.
;
;
Expunge_Device:
bug <10,"cnet: Expunge_Device $%08lx",10>,a6
ifgt 0
ifd debug
ifd verbose
move.l #100000,d0
.wait:
tst.b $bfe001
subq.l #1,d0
bne.s .wait
endc
endc
endc
tst.w lib_opencnt(a6)
beq.s .unload ; anyone has us open ?
; it is still open. set the delayed expunge flag
bug <"cnet: Could not expunge, LIBF_DELEXP set!",10>
bset #LIBB_DELEXP,lib_flags(a6)
moveq #0,d0 ; do not unload the seg
rts
.unload
bug <"cnet: Unloading...",10>
movem.l a4/a6,-(sp)
move.l dd_SegList(a6),-(sp) ; seglist to return in d0
move.l a6,a4
move.l exec_base(pc),a6
; put the hardware offline
move.l a4,a1
; a6=execbase
bug <"cnet: devclosedown",10>
bsr devclosedown
; get rid of the timer.device stuff we might have allocated:
lea timereq(pc),a1
move.l io_device(a1),d0
beq.s .notimerdev ; was timer ever opened?
addq.l #1,d0
beq.s .notimerdev ; error can be also indicated by -1!
bug <"cnet: closedevice timer ior $%08lx",10>,a1
jsr _LVOCloseDevice(a6) ; close it
.notimerdev
; release the card, if we own it. note that there is
; no CloseResource() call.
move.l dd_cardres(a4),d0 ; did we open card.resource at some point ?
beq.s .nocard
bclr #DDB_OWNED,dd_flags(a4) ; do we own card ?
beq.s .nocard
move.l a6,-(sp)
move.l d0,a6
lea dd_cardhandle(a4),a1
moveq #CARDF_REMOVEHANDLE,d0
bug <"cnet: releasing cardhandle $%08lx",10>,a1
jsr _LVOReleaseCard(a6) ; release card
move.l (sp)+,a6
.nocard:
; close utilitybase
move.l utility_base(pc),a1
bug <"cnet: closing utilitybase $%08lx",10>,a1
jsr _LVOCloseLibrary(a6)
; unlink from device list
move.l a4,a1
bug <"cnet: removing device node $%08lx",10>,a1
REMOVE
; free our memory (must calculate from LIB_POSSIZE & LIB_NEGSIZE)
moveq #0,d0
move.l a4,a1 ; devicebase
move.w lib_negsize(a4),d0
sub.l d0,a1 ; calculate base of functions
add.w lib_possize(a4),d0 ; calculate size of functions + data area
jsr _LVOFreeMem(a6)
bug <"cnet: Unload done! cnet.device expunged!",10,10>
movem.l (sp)+,d0/a4/a6 ; pop regs and seglist pointer
rts
;======================================================================
; devclosedown(device, execbase)
; a1 a6
;======================================================================
;
; Put the nic into sleep... also do whatever nececcary hw magic
; before device closedown. mark the device offline and unconfigured.
;
devclosedown:
;and.b #~(DDF_ONLINE|DDF_CONFIGURED),dd_flags(a1) ; not online, not configured
and.b #~DDF_ONLINE,dd_flags(a1) ; not online
and.b #~(DDF_MINE|DDF_PROM),dd_flags2(a1) ; cancel exclusive mode, cancel promiscuous mode
bra kill_nic ; stop controller
;===============================================================
; Dev_BeginIO
;===============================================================
; the entry point for all device commands
;
CNOP 0,4
_DevBeginIO:
move.w io_command(a1),d0 ; get command number
move.b #NT_MESSAGE,ln_type(a1) ; make sure type is message
cmp.w #S2_END,d0
bhs .berror ; valid command?
lsl.w #2,d0
move.l .cmds(pc,d0.w),d0 ; get command vector
bne.s .ok
.error:
move.b #IOERR_NOCMD,io_error(a1)
bra TermIO ; return invalid command
.ok:
move.l d0,a0
clr.b io_error(a1) ; no errors yet
ifgt 0
ifd debug
ifd verbose
moveq #0,d0
move.w io_command(a1),d0
bug <"cnet: BeginIO ioreq $%08lx cmd %ld",10>,a1,d0
move.l #300000,d0
.wait:
tst.b $bfe001
subq.l #1,d0
bne.s .wait
endc
endc
endc
jmp (a0) ; jump to command
; command vectors
CNOP 0,4
.cmds:
dc.l 0 ; 0
dc.l 0 ; 1
dc.l devcmd_read ; 2 = cmd_read
dc.l devcmd_write ; 3 = cmd_write
dc.l 0 ; 4
dc.l 0 ; 5
dc.l 0 ; 6
dc.l 0 ; 7
dc.l devcmd_flush ; 8 = cmd_flush
dc.l devcmd_devicequery ; 9 = S2_DEVICEQUERY
dc.l devcmd_getstationaddress ; 10= S2_GETSTATIONADDRESS
dc.l devcmd_configinterface ; 11= S2_CONFIGINTERFACE
dc.l 0 ; 12
dc.l 0 ; 13
dc.l devcmd_addmulticast ; 14= S2_ADDMULTICASTADDRESS
dc.l devcmd_delmulticast ; 15= S2_DELMULTICASTADDRESS
dc.l devcmd_multicast ; 16= S2_MULTICAST
dc.l devcmd_broadcast ; 17= S2_BROADCAST
dc.l devcmd_tracktype ; 18= S2_TRACKTYPE
dc.l devcmd_untracktype ; 19= S2_UNTRACKTYPE
dc.l devcmd_gettypestats ; 20= S2_GETTYPESTATS
dc.l devcmd_getspecialstats ; 21= S2_GETSPECIALSTATS
dc.l devcmd_getglobalstats ; 22= S2_GETGLOBALSTATS
dc.l devcmd_onevent ; 23= S2_ONEVENT
dc.l devcmd_readorphan ; 24= S2_READORPHAN
dc.l devcmd_online ; 25= S2_ONLINE
dc.l devcmd_offline ; 26= S2_OFFLINE
.nsd_supported:
dc.w 2,3
dc.w 8,9,10,11
dc.w 14,15,16,17,18,19,20,21,22,23,24,25,26
dc.w NSCMD_DEVICEQUERY
dc.w S2_ADDMULTICASTADDRESSES
dc.w S2_DELMULTICASTADDRESSES
dc.w 0
.berror:
clr.b io_error(a1) ; no error
cmp.w #S2_ADDMULTICASTADDRESSES,d0
beq devcmd_addmulticasts
cmp.w #S2_DELMULTICASTADDRESSES,d0
beq devcmd_delmulticasts
cmp.w #NSCMD_DEVICEQUERY,d0 ; is it NSCMD_DEVICEQUERY?
bne .error
ifd verbose
bug <"cnet: NSCMD_DEVICEQUERY ior $%08lx",10>,a1
endc
cmp.l #16,io_length(a1)
blt .error
move.l io_data(a1),d0
beq .error
move.l d0,a0
tst.l (a0)+
bne .error
tst.l (a0)
bne .error
ifd verbose
bug <"cnet: replied with NSDEVTYPE_SANA2!",10>
endc
moveq #16,d0
move.l d0,(a0)+
move.l #$00070000,(a0)+ ; NSDEVTYPE_SANA2<<16
move.l #.nsd_supported,(a0)
move.l d0,io_actual(a1)
bra TermIO
;====================================================================
; Abort_IO
;====================================================================
;
; try to cancel a pending ioreq
;
_DevAbortIO:
bug <"cnet: AbortIO ioreq $%08lx",10>,a1
movem.l d2/a2-a4/a6,-(sp)
move.l a6,a4 ; a4=device
move.l exec_base(pc),a6
move.l a1,a2 ; a2=ioreq
moveq #0,d0 ; if already replied silentry ignore
MYDISABLE ; lock access to lists
cmp.b #NT_MESSAGE,ln_type(a2) ; only cancel queued ioreq's
bne.s .done
move.w io_command(a2),d0
cmp.w #CMD_READ,d0
beq.s .read
lea dd_orphanlist(a4),a0
cmp.w #S2_READORPHAN,d0
beq.s .thisone
lea dd_writelist(a4),a0
cmp.w #CMD_WRITE,d0
beq.s .thisone
cmp.w #S2_MULTICAST,d0
beq.s .thisone
cmp.w #S2_BROADCAST,d0
beq.s .thisone
lea dd_eventlist(a4),a0
cmp.w #S2_ONEVENT,d0
beq.s .thisone
bug <"cnet: AbortIO not READ, READORPHAN, WRITE, MULTICAST, BROADCAST or ONEVENT",10>
moveq #IOERR_NOCMD,d0
bra.s .done
.read:
; Check all nodes in dd_bufmanlist until we succeed to abort:
; if we can't find the ioreq in any list, return IOERR_NOCMD.
move.l dd_bufmanlist(a4),a3
;bug <"cnet: AbortIO READ bufmanlist 1st: $%08lx",10>,a3
.readhandle
moveq #IOERR_NOCMD,d0 ; return failure if we can't find it
move.l (a3),d2
beq.s .done ; end of list?
lea bufman_rxqueue(a3),a0
; a2=ioreq
bsr AbortReq
tst.l d0
beq.s .done ; succeeded to abort?
move.l d2,a3
bra.s .readhandle
.thisone:
; a0=list where the ioreqs should be in
; a2=ioreq
bsr AbortReq
.done:
MYENABLE ; release lock on lists
movem.l (sp)+,d2/a2-a4/a6
rts
;======================================================================
; AbortReq(minlist, ioreq, execbase)
; a0 a2 a6
;======================================================================
;
; locate an IO request in a linked list and abort it if found.
;
AbortReq:
moveq #IOERR_NOCMD,d0
move.l (a0),a0
.search:
move.l (a0),d1
beq.s .done ; end of list ?
cmp.l a2,a0 ; = ioreq ?
move.l d1,a0 ; note: movea doesn't change ccs!
bne.s .search
move.l a2,a1
;bug <"cnet: AbortReq aborted $%08lx",10>,a1
REMOVE ; remove ioreq from list
move.b #NT_REPLYMSG,ln_type(a2)
move.b #IOERR_ABORTED,io_error(a2)
move.l a2,a1
jsr _LVOReplyMsg(a6) ; reply to originator's message
moveq #0,d0 ; aborted OK
.done:
rts
;===========================================================
; termio(ioreq)
; a1
;===========================================================
;
; return completed ioreq to sender.
;
TermIO:
move.b #NT_REPLYMSG,ln_type(a1)
btst #IOB_QUICK,io_flags(a1)
bne.s .done ; does sender need a reply ?
move.l a6,-(sp)
move.l exec_base(pc),a6
jsr _LVOReplyMsg(a6) ; send reply
move.l (sp)+,a6
.done:
rts
;====================================================
; CMD_READ
;====================================================
;
; if card is configured and online
;
CNOP 0,4
devcmd_read:
ifd verbose
bug <"cnet: cmd_read(ior $%08lx, type %ld)",10>,a1,ios2_packettype(a1)
endc
movem.l a2/a3/a6,-(sp)
move.l a1,a2 ; a2 = ioreq
move.l io_device(a1),a3 ; a3 = device
btst #DDB_CONFIGURED,dd_flags(a3) ; configured ?
beq .unconfigured
btst #DDB_ONLINE,dd_flags(a3) ; online ?
beq .offline
move.l ios2_buffermanagement(a2),d0
beq.s .bad ; eeeekh, no bufman ?
move.l d0,a0
tst.l bufman_copytobuf(a0)
beq.s .bad ; this is needed for reading.. :)
bclr #IOB_QUICK,io_flags(a2) ; must be queued
move.l exec_base(pc),a6
; add to this ioreq's bufman_rxqueue
lea bufman_rxqueue(a0),a0
move.l a2,a1
ifd verbose
bug <"cnet: CMD_READ ior $%08lx added to bufman_rxqueue $%08lx",10>,a1,a0
endc
MYDISABLE
ADDTAIL ; add ioreq to read queue
MYENABLE
.done:
movem.l (sp)+,a2/a3/a6
rts
.unconfigured:
moveq #S2WERR_NOT_CONFIGURED,d0 ; error, device is not configured
move.b #S2ERR_BAD_STATE,io_error(a2)
bra.s .error
.offline:
moveq #S2WERR_UNIT_OFFLINE,d0 ; error, device is offline
move.b #S2ERR_OUTOFSERVICE,io_error(a2)
bra.s .error
.bad:
moveq #S2WERR_GENERIC_ERROR,d0 ; error, bad argument
move.b #S2ERR_BAD_ARGUMENT,io_error(a2)
.error:
ifd verbose
bug <"cnet: read ior $%08lx error %ld",10>,a2,d0
endc
move.l d0,ios2_wireerror(a2)
move.l a2,a1
bsr TermIO
bra.s .done
;====================================================
; S2_READORPHAN
;====================================================
;
; if card is configured and online
;
CNOP 0,4
devcmd_readorphan:
bug <"cnet: readorphan(ior $%08lx, type %ld)",10>,a1,ios2_packettype(a1)
movem.l a2/a3/a6,-(sp)
move.l a1,a2 ; a2 = ioreq
move.l io_device(a2),a3
btst #DDB_CONFIGURED,dd_flags(a3) ; configured ?
beq .unconfigured
btst #DDB_ONLINE,dd_flags(a3) ; online ?
beq .offline
move.l ios2_buffermanagement(a2),d0
beq.s .bad ; eeeekh, no bufman ?
move.l d0,a0
tst.l bufman_copytobuf(a0)
beq.s .bad ; this is needed for reading.. :)
bclr #IOB_QUICK,io_flags(a2) ; must be queued
move.l exec_base(pc),a6
lea dd_orphanlist(a3),a0
move.l a2,a1
bug <"cnet: S2_READORPHAN ior $%08lx added to orphanlist $%08lx",10>,a1,a0
MYDISABLE
ADDTAIL ; add ioreq to orphan queue
MYENABLE
.done:
movem.l (sp)+,a2/a3/a6
rts
.unconfigured:
moveq #S2WERR_NOT_CONFIGURED,d0 ; error, device is not configured
move.b #S2ERR_BAD_STATE,io_error(a2)
bra.s .error
.offline:
moveq #S2WERR_UNIT_OFFLINE,d0 ; error, device is offline
move.b #S2ERR_OUTOFSERVICE,io_error(a2)
bra.s .error
.bad:
moveq #S2WERR_GENERIC_ERROR,d0 ; error, bad argument
move.b #S2ERR_BAD_ARGUMENT,io_error(a2)
.error:
ifd verbose
bug <"cnet: readorphan ior $%08lx error %ld",10>,a2,d0
endc
move.l d0,ios2_wireerror(a2)
move.l a2,a1
bsr TermIO
bra.s .done
;======================================================
; CMD_WRITE
;======================================================
;
; if card is configured and online
;
CNOP 0,4
devcmd_write:
ifd verbose
bug <"cnet: cmd_write(ior $%08lx, type %ld)",10>,a1,ios2_packettype(a1)
endc
movem.l a2/a3/a6,-(sp)
move.l a1,a2 ; a2 = ioreq
move.l io_device(a2),a3 ; a3 = device
btst #DDB_CONFIGURED,dd_flags(a3) ; configured ?
beq .unconfigured
btst #DDB_ONLINE,dd_flags(a3) ; online ?
beq .offline
; check ioreq's bufman validity
move.l ios2_buffermanagement(a2),d0
beq.s .bad ; eeeekh, no bufman ?
move.l d0,a0
tst.l bufman_copyfrombuf(a0)
beq.s .bad ; no routine for writing ?
move.l ios2_DataLength(a2),d1
tst.b io_flags(a2) ; (test SANA2IOB_RAW) raw packets ?
bpl.s .cooked
cmp.l #RAWPKT_SIZE,d1
bls.s .goodlen ; check packet size
bra.s .toobig
.cooked:
cmp.l #ETHERPKT_SIZE,d1
bhi.s .toobig
.goodlen:
bclr #IOB_QUICK,io_flags(a2) ; must be queued
move.l exec_base(pc),a6
lea dd_writelist(a3),a0
move.l a2,a1
ifd verbose
bug <"cnet: CMD_WRITE ior $%08lx added to writelist $%08lx",10>,a1,a0
endc
MYDISABLE
ADDTAIL ; add ioreq to write queue
MYENABLE
lea dd_txint(a3),a1
jsr _LVOCause(a6) ; start tx
.done:
movem.l (sp)+,a2/a3/a6
rts
.unconfigured:
moveq #S2WERR_NOT_CONFIGURED,d0 ; error, not configured
move.b #S2ERR_BAD_STATE,io_error(a2)
bra.s .error
.offline:
moveq #S2WERR_UNIT_OFFLINE,d0 ; error, device is offline
move.b #S2ERR_OUTOFSERVICE,io_error(a2)
bra.s .error
.bad:
moveq #S2WERR_GENERIC_ERROR,d0 ; error, bad argument
move.b #S2ERR_BAD_ARGUMENT,io_error(a2)
bra.s .error
.toobig:
moveq #S2EVENT_TX,d0 ; return any TX events
bsr DoEvent
moveq #0,d0
move.b #S2ERR_MTU_EXCEEDED,io_error(a2) ; oops! packet too big
.error:
ifd verbose
bug <"cnet: write ior $%08lx error %ld",10>,a2,d0
endc
move.l d0,ios2_wireerror(a2)
move.l a2,a1
bsr TermIO
bra.s .done
;==============================================
; CMD_FLUSH
;==============================================
;
devcmd_flush:
movem.l a1-a2/a6,-(sp)
move.l exec_base(pc),a6
move.l io_device(a1),a2 ; a2 = device
bug <"cnet: CMD_FLUSH ior $%08lx device $%08lx",10>,a1,a2
ifgt 0
ifd debug
ifd verbose
bug <"cnet: delaying...",10>
move.l #500000,d0
.wait:
tst.b $bfe001
subq.l #1,d0
bne.s .wait
endc
endc
endc
MYDISABLE
move.l a2,a0
moveq #IOERR_ABORTED,d0
moveq #0,d1
bsr AbortRW
lea dd_eventlist(a2),a0 ; abort all Event requests
moveq #IOERR_ABORTED,d0
moveq #0,d1
bsr AbortList
MYENABLE
bug <"cnet: CMD_FLUSH done",10>
movem.l (sp)+,a1-a2/a6
bra TermIO
;======================================================================
; abortlist(list, errcode, wireerror, execbase)
; a0 d0.b d1.l a6
;======================================================================
;
; Aborts all ios2requs in given list with ios2_Error set to errcode
; and ios2_wireerror set to wireerror.
;
AbortList:
movem.l d2-d3/a2,-(sp)
move.l a0,a2
move.b d0,d2
move.l d1,d3
bra.s .flush
.loop:
move.l d0,a1
;move.b #NT_REPLYMSG,ln_type(a1)
move.b d2,io_error(a1)
move.l d3,ios2_wireerror(a1)
;bug <"cnet: AbortList ior $%08lx",10>,a1
jsr _LVOReplyMsg(a6)
.flush:
move.l a2,a0
MYREMHEAD
bne.s .loop
movem.l (sp)+,d2-d3/a2
rts
;======================================================================
; abortrw(device, errcode, wireerror, execbase)
; a0 d0.b d1.l a6
;======================================================================
;
; Aborts all pending reads and writes with ios2_Error set to errcode
; and ios2_wireerror set to wireerror.
;
AbortRW:
movem.l d2-d4/a2-a3,-(sp)
move.l a0,a3
move.b d0,d2
move.l d1,d3
move.l dd_bufmanlist(a3),a2
.reado:
move.l (a2),d4
beq.s .flushrest
bra.s .flushreads
.readloop:
move.l d0,a1
;move.b #NT_REPLYMSG,ln_type(a1)
move.b d2,io_error(a1)
move.l d3,ios2_wireerror(a1)
;bug <"cnet: AbortRead ior $%08lx",10>,a1
jsr _LVOReplyMsg(a6) ; abort all Read requests
.flushreads:
lea bufman_rxqueue(a2),a0
MYREMHEAD
bne.s .readloop
move.l d4,a2
bra.s .reado
.flushrest:
lea dd_orphanlist(a3),a0 ; abort all ReadOrphan requests
move.b d2,d0
move.l d3,d1
bsr AbortList
lea dd_writelist(a3),a0 ; abort all Write requests
move.b d2,d0
move.l d3,d1
bsr AbortList
movem.l (sp)+,d2-d4/a2-a3
rts
;==============================================
; S2_ONLINE
;==============================================
;
; Try to put device online
;
devcmd_online:
bug <"cnet: s2_online",10>
move.l a1,-(sp)
move.l io_device(a1),a0 ; a0 = device
; This is a workaround for Genesis.. it calls
; S2_ONLINE before S2_CONFIGINTERFACE.
btst #DDB_ONLINE,dd_flags(a0) ; already online ?
bne.s .done
btst #DDB_CONFIGURED,dd_flags(a0) ; won't go online unless configured!
beq.s .unconfigured
btst #DDB_NICUP,dd_flags(a0) ; nic initialised ?
beq.s .uninit
bclr #DDB_OFFLINE,dd_flags(a0)
bset #DDB_ONLINE,dd_flags(a0) ; mark being online
move.b dd_rcr(a0),nic_rcr ; set receiver to normal mode
moveq #S2EVENT_ONLINE,D0
bsr DoEvent ; return any ONLINE events
.done:
move.l (sp)+,a1
bra TermIO
.unconfigured:
moveq #S2WERR_NOT_CONFIGURED,d0 ; error, device is not configured
move.b #S2ERR_BAD_STATE,io_error(a2)
bra.s .error
.uninit:
moveq #S2WERR_UNIT_OFFLINE,d0
move.b #S2ERR_OUTOFSERVICE,io_error(a1)
.error:
move.l d0,ios2_wireerror(a1)
bra.s .done
;==============================================
; S2_OFFLINE
;==============================================
;
; take device offline
;
;
devcmd_offline:
bug <"cnet: s2_offline",10>
movem.l a1/a6,-(sp)
move.l io_device(a1),a0 ; a0 = device
bset #DDB_OFFLINE,dd_flags(a0)
bclr #DDB_ONLINE,dd_flags(a0) ; already offline ?
beq.s .done
btst #DDB_NICUP,dd_flags(a0)
beq.s .nicoff
move.b #DSRC_MON,nic_rcr ; set receiver to monitor mode
.nicoff:
move.l exec_base(pc),a6
bug <"cnet: s2_offline **NOT** aborting read/readorphan/write requests!",10>
ifgt 0
MYDISABLE
; a0=device
moveq #S2ERR_OUTOFSERVICE,d0
moveq #S2WERR_UNIT_OFFLINE,d1
bsr AbortRW
MYENABLE
endc
moveq #S2EVENT_OFFLINE,d0
bsr DoEvent ; return any OFFLINE events
.done:
movem.l (sp)+,a1/a6
bra TermIO
;==============================================
; S2_ONEVENT
;==============================================
;
; queue up event requests
;
; online/offline return immediately if the conditon is met.
;
devcmd_onevent:
bug <"cnet: s2_onevent mask $%08lx",10>,ios2_wireerror(a1)
movem.l a1/a3/a6,-(sp)
move.l io_device(a1),a3 ; a3 = device
; do we know the requested events?
move.l ios2_wireerror(a1),d0
and.l #~(S2EVENT_ERROR|S2EVENT_TX|S2EVENT_RX|S2EVENT_ONLINE|S2EVENT_OFFLINE|S2EVENT_BUFF|S2EVENT_HARDWARE),d0
bne .unknown
move.l ios2_wireerror(a1),d0
and.l #S2EVENT_ONLINE,d0 ; waiting for online event ?
beq.s .noton
btst #DDB_ONLINE,dd_flags(a3) ; currently online ?
bne.s .rtn
bra.s .queue
.noton:
move.l ios2_wireerror(a1),d0
and.l #S2EVENT_OFFLINE,d0 ; waiting for offline event ?
beq.s .queue
btst #DDB_ONLINE,dd_flags(a3) ; currently offline ?
bne.s .queue
.rtn:
bug <"is (on|off)line",10>
move.l d0,ios2_wireerror(a1) ; return immediately
;already! clr.b io_error(a1)
.term:
bsr TermIO
bra.s .done
.queue:
bug <"queued",10>
bclr #IOB_QUICK,io_flags(a1) ; must be queued
move.l exec_base(pc),a6
lea dd_eventlist(a3),a0
MYDISABLE
ADDTAIL ; add ioreq to event queue
MYENABLE
.done:
movem.l (sp)+,a1/a3/a6
rts
.unknown:
bug <"unknown events requested!",10>
moveq #S2WERR_BAD_EVENT,d0
move.b #S2ERR_NOT_SUPPORTED,io_error(a1)
move.l d0,ios2_wireerror(a1)
bra.s .term
;==============================================
; S2_DEVICEQUERY
;==============================================
;
devcmd_devicequery:
bug <"cnet: s2_devicequery",10>
move.l a1,-(sp)
move.l ios2_statdata(a1),a0 ; a0 = caller's buffer
move.l (a0),d1 ; d1 = buffer size
move.l size_supplied(pc),d0
cmp.l d0,d1 ; enough space to store info?
bhs.s .get
clr.l S2DQ_SIZESUPPLIED(a0) ; nope!
.bad:
moveq #S2WERR_BAD_STATDATA,d0
move.b #S2ERR_BAD_ARGUMENT,io_error(a1)
move.l d0,ios2_wireerror(a1)
bra.s .done
.get:
lea S2DQ_SIZESUPPLIED(a0),a1
lea size_supplied(pc),a0
subq.l #4,d0 ; skip bytes_available
bra.s .copy
.copyloop:
move.b (a0)+,(a1)+ ; copy info to caller's buffer
.copy:
subq.w #1,d0
bpl.s .copyloop
.done:
move.l (sp)+,a1
bra TermIO
;==============================================
; S2_GETSTATIONADDRESS
;==============================================
;
devcmd_getstationaddress:
bug <"cnet: s2_getstationaddress",10>
move.l io_device(a1),a0
move.l a1,-(sp)
lea dd_stationaddress(a0),a0
lea ios2_srcaddr(a1),a1 ; source address = station address
bsr.s .makeit
subq.l #ETHER_ADDR_SIZE,a0 ; dest address = default address
bsr.s .makeit
move.l (sp)+,a1
bra TermIO
.makeit:
move.l (a0)+,(a1)+
move.w (a0)+,(a1)+
clr.w (a1)+
clr.l (a1)+
clr.l (a1)+
rts
;==============================================
; S2_CONFIGINTERFACE
;==============================================
;
; NOTE: a default station address has already
; been set by init_nic
;
devcmd_configinterface:
bug <"cnet: s2_configinterface",10>
move.l io_device(a1),a0
bset #DDB_CONFIGURED,dd_flags(a0) ; already configured ?
bne .already
move.l a6,-(sp)
move.l exec_base(pc),a6
MYDISABLE
move.l ios2_srcaddr(a1),d0
ble .badaddr ; check for valid address
lea dd_stationaddress(a0),a0
move.l d0,(a0)
move.w ios2_srcaddr+4(a1),4(a0)
move.b nic_cr,d1 ; remember current command
delay
move.b #DSCM_NODMA|DSCM_PG1,nic_cr ; select bank 1
delay
move.b (a0)+,nic_par0
delay
move.b (a0)+,nic_par1
delay
move.b (a0)+,nic_par2
delay ; set station address
move.b (a0)+,nic_par3
delay
move.b (a0)+,nic_par4
delay
move.b (a0),nic_par5
delay
move.b d1,nic_cr ; restore command
.done:
MYENABLE
move.l (sp)+,a6
.termit:
bra TermIO
.badaddr:
bclr #DDB_CONFIGURED,dd_flags(a0) ; NOT configured!
moveq #S2WERR_SRC_ADDRESS,d0 ; error, source address bad
move.b #S2ERR_BAD_ADDRESS,io_error(a1)
move.l d0,ios2_wireerror(a1)
bra.s .done
.already
moveq #S2WERR_IS_CONFIGURED,d0 ; error, already configured
move.b #S2ERR_BAD_STATE,io_error(a1)
move.l d0,ios2_wireerror(a1)
bra.s .termit
;==============================================
; S2_MULTICAST
;==============================================
;
devcmd_multicast:
bug <"cnet: s2_multicast %08lx%04x",10>,ios2_dstaddr(a1),ios2_dstaddr+2(a1)
btst #0,ios2_dstaddr(a1) ; is dest a multicast address ?
bne devcmd_write
move.l a1,-(sp)
moveq #S2EVENT_TX,d0 ; return any TX events
bsr DoEvent
move.l (sp)+,a1
moveq #S2WERR_BAD_MULTICAST,d0 ; wasn't a multicast addr
move.b #S2ERR_BAD_ADDRESS,io_error(a1)
move.l d0,ios2_wireerror(a1)
bra TermIO
;==============================================
; S2_BROADCAST
;==============================================
;
devcmd_broadcast:
bug <"cnet: s2_broadcast",10>
moveq #-1,d0
move.l d0,ios2_dstaddr+0(a1) ; dest address = BROADCAST (255)
move.w d0,ios2_dstaddr+4(a1) ; dest address = BROADCAST (255)
bra devcmd_write
;============================================
; S2_TRACKTYPE
;============================================
;
; This function adds a packet type to the
; list of those that are being tracked.
;
devcmd_tracktype:
bug <"cnet: s2_tracktype %ld",10>,ios2_packettype(a1)
movem.l a2/a3/a6,-(sp)
move.l exec_base(pc),a6
move.l a1,a2 ; a2 = ioreq
move.l io_device(a1),a3
move.l ios2_packettype(a2),d0 ; d0 = our packet type
MYDISABLE ; lock access to list
move.l dd_tracklist(a3),a0 ; a0 = 1st entry in list
bra.s .start
.search:
cmp.l ss2_ptype(a0),d0 ; = our packet type ?
beq.s .duperr
move.l d1,a0
.start:
move.l (a0),d1
bne.s .search ; end of list ?
moveq #ss2_sizeof,d0
move.l #MEMF_PUBLIC|MEMF_CLEAR,d1
jsr _LVOAllocMem(a6) ; allocmem for tracking node
tst.l d0
beq.s .nomem
move.l d0,a1 ; a1 = new entry
move.l ios2_packettype(a2),ss2_ptype(a1) ; set tracking type
lea dd_tracklist(a3),a0
ADDTAIL ; add new tracktype node to list
.done:
MYENABLE ; release lock on lists
move.l a2,a1
movem.l (sp)+,a2/a3/a6
bra TermIO
.nomem:
moveq #S2WERR_NOT_TRACKED,d0
move.b #S2ERR_NO_RESOURCES,io_error(a2)
bra.s .error ; error, can't allocate memory!
.duperr:
moveq #S2WERR_ALREADY_TRACKED,d0
move.b #S2ERR_BAD_STATE,io_error(a2)
.error:
move.l d0,ios2_wireerror(a2) ; error, type is tracked already!
bra.s .done
;==============================================
; S2_UNTRACKTYPE
;==============================================
;
; This function removes a packet type from the
; list of those that are being tracked.
;
devcmd_untracktype:
bug <"cnet: s2_untracktype %ld",10>,ios2_packettype(a1)
movem.l a2-a3/a6,-(sp)
move.l exec_base(pc),a6
move.l a1,a2 ; a2 = ioreq
move.l io_device(a1),a0
move.l ios2_packettype(a2),d0 ; d0 = packet type to untrack
MYDISABLE ; lock access to list
move.l dd_tracklist(a0),a3 ; a3 = 1st entry in tracking list
bra.s .start
.search:
cmp.l ss2_ptype(a3),d0 ; found our packet type ?
beq.s .found
move.l d1,a3 ; a3 = next entry
.start:
move.l (a3),d1
bne.s .search ; end of list?
bra.s .error
.found:
move.l a3,a1
REMOVE ; remove entry from list
move.l a3,a1
moveq #ss2_sizeof,d0
jsr _LVOFreeMem(a6) ; free entry's memory
.done:
MYENABLE ; unlock access to list
move.l a2,a1
movem.l (sp)+,a2-a3/a6
bra TermIO
.error:
moveq #S2WERR_NOT_TRACKED,d0 ; error, no tracktype!
move.b #S2ERR_BAD_STATE,io_error(a2)
move.l d0,ios2_wireerror(a2)
bra.s .done
;==================================================
; S2_GETTYPESTATS
;==================================================
; This function returns statistics for a specific
; type of packet that is being tracked.
;
devcmd_gettypestats:
bug <"cnet: s2_gettypestats",10>
movem.l a2/a6,-(sp)
move.l exec_base(pc),a6
move.l a1,a2 ; a2 = ioreq
move.l io_device(a1),a0
move.l ios2_packettype(a2),d0 ; d0 = packettype
MYDISABLE ; lock access to list
move.l dd_tracklist(a0),a0 ; a0 = 1st entry in tracking list
bra.s .start
.loop:
move.l d1,a0 ; a0 = next entry
.start:
move.l (a0),d1 ; end of list ?
beq.s .notfound
cmp.l ss2_ptype(a0),d0 ; found our track type ?
bne.s .loop
; note that both ss2_stats and ios2_statdata are quaranteed to be
; word aligned.
lea ss2_stats(a0),a0
move.l ios2_statdata(a2),a1
moveq #s2pts_size/4,d0
.copystats
move.l (a0)+,(a1)+ ; copy stats to ioreq
subq.l #1,d0
bne.s .copystats
.done:
MYENABLE ; release lock on list
move.l a2,a1
movem.l (sp)+,a2/a6
bra TermIO
.notfound:
moveq #S2WERR_NOT_TRACKED,d0
move.b #S2ERR_BAD_STATE,io_error(a2)
move.l d0,ios2_wireerror(a2) ; error, couldn't find track type
bra.s .done
;==============================================
; S2_GETSPECIALSTATS
;==============================================
;
devcmd_getspecialstats:
bug <"cnet: s2_getspecialstats",10>
movem.l a1-a2,-(sp)
move.l io_device(a1),a2 ; a2 = unit
move.l ios2_statdata(a1),a1
clr.l s2ssh_recordcountsupplied(a1)
move.l (a1)+,d0 ; check s2ssh_recordcountmax
beq.s .done
addq.l #1,(a1)+ ; s2ssh_recordcountsupplied++
move.l a1,a0
move.l #S2SS_ETHERNET_BADMULTICAST,(a0)+ ; set type }
move.l dd_badmulticasts(a2),(a0)+ ; set statistic } bad multi
move.l #multiname,(a0)+ ; set name }
subq.l #1,d0
beq.s .done ; want more ?
addq.l #1,-(a1) ; s2ssh_recordcountsupplied++
move.l #S2SS_ETHERNET_RETRIES,(a0)+ ; set type }
move.l dd_retries(a2),(a0)+ ; set statistic } retries
move.l #retryname,(a0)+ ; set name }
.done:
movem.l (sp)+,a1-a2
bra TermIO
;==============================================
; S2_GETGLOBALSTATS
;==============================================
;
devcmd_getglobalstats:
bug <"cnet: s2_getglobalstats",10>
move.l a1,-(sp)
move.l io_device(a1),a0
; note that both dd_devicestats and ios2_statdata are quaranteed to be
; word aligned.
;
lea dd_devicestats(a0),a0
move.l ios2_statdata(a1),a1
moveq #s2ds_size/4,d0
.copy:
move.l (a0)+,(a1)+ ; get sana2devicestats
subq.l #1,d0
bne.s .copy
move.l (sp)+,a1
bra TermIO
;==========================================================
; get_time
;==========================================================
;
; in: a0 = pointer to timeval struct
;
; get current time_of_day
;
get_time:
move.l timereq+io_device(pc),d0
movem.l a2/a6,-(sp)
beq.s .open ; io_device <> 0 ?
addq.l #1,d0
move.l a0,a2
bne.s .gotdev ; io_device <> -1 ?
.open:
move.l exec_base(pc),a6
lea timerdevname(pc),a0
lea timereq(pc),a1
moveq #UNIT_VBLANK,d0
move.b #NT_MESSAGE,ln_type(a1)
moveq #0,d1
move.w #iotv_size,mn_length(a1)
jsr _LVOOpenDevice(a6)
tst.l d0
bne.s .done
.gotdev:
lea timereq(pc),a1
move.l io_device(a1),a6
move.l a2,a0
jsr _LVOGetSysTime(a6)
.done:
movem.l (sp)+,a2/a6
rts
;==============================================
; S2_ADDMULTICASTADDRESS
;==============================================
;
devcmd_addmulticast:
bug <"cnet: s2_addmulticastaddress %08lx%04x",10>,ios2_srcaddr(a1),ios2_srcaddr+2(a1)
move.l ios2_srcaddr+4(a1),-(sp) ; lower = upper !
move.l ios2_srcaddr(a1),-(sp)
move.l ios2_srcaddr+4(a1),-(sp)
move.l ios2_srcaddr(a1),-(sp)
addmcast:
movem.l a2-a4/a6,-(sp)
move.l a6,a3 ; a3 = device
move.l exec_base(pc),a6
move.l a1,a4 ; a4 = ioreq
bsr.s addmcastrange
move.l a4,a1
movem.l (sp)+,a2-a4/a6
lea 4*4(sp),sp
bra TermIO
;==============================================
; S2_ADDMULTICASTADDRESSES
;==============================================
;
devcmd_addmulticasts:
bug <"cnet: s2_addmulticastaddresses %08lx%04x - %08lx%04x",10>,ios2_srcaddr(a1),ios2_srcaddr+2(a1),ios2_dstaddr(a1),ios2_dstaddr+2(a1)
move.l ios2_dstaddr+4(a1),-(sp) ; upper
move.l ios2_dstaddr(a1),-(sp)
move.l ios2_srcaddr+4(a1),-(sp) ; lower
move.l ios2_srcaddr(a1),-(sp)
bra.s addmcast
AMCRO EQU 4+(4*4)
addmcastrange:
btst #0,AMCRO+0+0(sp) ; is src a multicast address ?
beq.s .badmcast
btst #0,AMCRO+8+0(sp) ; is dst a multicast address ?
beq.s .badmcast
lea dd_multicastssema(a3),a0
jsr _LVOObtainSemaphore(a6) ; lock access to list
move.l dd_multicasts(a3),a0 ; a0 = first entry in multicast list
bra.s .getmulti
.check:
move.l AMCRO+0+0(sp),d0
cmp.l mcastar_loweraddr(a0),d0
bne.s .next
move.w AMCRO+0+4(sp),d0
cmp.w mcastar_loweraddr+4(a0),d0
bne.s .next
move.l AMCRO+8+0(sp),d0 ; is our address in an existing entry ?
cmp.l mcastar_upperaddr(a0),d0
bne.s .next
move.w AMCRO+8+4(sp),d0
cmp.w mcastar_upperaddr+4(a0),d0
bne.s .next
addq.l #1,mcastar_count(a0) ; added same address again
ifd debug
move.l mcastar_count(a0),d0
bug <"cnet: mcast node $%lx count=%ld",10>,a0,d0
endc
bra .unlock
.next:
move.l d1,a0 ; get next node in list
.getmulti:
move.l (a0),d1 ; end of list ?
bne.s .check
moveq #mcastar_sizeof,d0
move.l #MEMF_PUBLIC|MEMF_CLEAR,d1
jsr _LVOAllocMem(a6) ; allocate memory for multicast entry
tst.l d0
beq.s .nomem
move.l d0,a1 ; a1 = new entry
move.w #1,mcastar_count+2(a1) ; count = 1
move.l AMCRO+0+0(sp),mcastar_loweraddr(a1)
move.w AMCRO+0+4(sp),mcastar_loweraddr+4(a1)
move.l AMCRO+8+0(sp),mcastar_upperaddr(a1)
move.w AMCRO+8+4(sp),mcastar_upperaddr+4(a1)
bug <"cnet: new mcast node at $%08lx",10>,a1
lea dd_multicasts(a3),a0
ADDTAIL ; add to list
move.l a3,a0
bsr update_multicasts ; update multicasts in nic
.unlock
lea dd_multicastssema(a3),a0
jmp _LVOReleaseSemaphore(a6) ; release lock on list
.badmcast:
moveq #S2WERR_BAD_MULTICAST,d0
move.b #S2ERR_BAD_ADDRESS,io_error(a4)
move.l d0,ios2_wireerror(a4) ; invalid multicast address
rts
.nomem:
moveq #S2WERR_GENERIC_ERROR,d0
move.b #S2ERR_NO_RESOURCES,io_error(a4)
move.l d0,ios2_wireerror(a4)
bra.s .unlock
;==============================================
; S2_DELMULTICASTADDRESS
;==============================================
;
devcmd_delmulticast:
bug <"cnet: s2_delmulticastaddress %08lx%04x",10>,ios2_srcaddr(a1),ios2_srcaddr+2(a1)
move.l ios2_srcaddr+4(a1),-(sp) ; lower = upper !
move.l ios2_srcaddr(a1),-(sp)
move.l ios2_srcaddr+4(a1),-(sp)
move.l ios2_srcaddr(a1),-(sp)
remmcast:
movem.l a2-a4/a6,-(sp)
move.l a6,a3 ; a3 = device
move.l exec_base(pc),a6
move.l a1,a4 ; a4 = ioreq
bsr.s delmcastrange
move.l a4,a1
movem.l (sp)+,a2-a4/a6
lea 4*4(sp),sp
bra TermIO
;==============================================
; S2_DELMULTICASTADDRESSES
;==============================================
;
devcmd_delmulticasts:
bug <"cnet: s2_delmulticastaddresses %08lx%04x - %08lx%04x",10>,ios2_srcaddr(a1),ios2_srcaddr+2(a1),ios2_dstaddr(a1),ios2_dstaddr+2(a1)
move.l ios2_dstaddr+4(a1),-(sp) ; upper
move.l ios2_dstaddr(a1),-(sp)
move.l ios2_srcaddr+4(a1),-(sp) ; lower
move.l ios2_srcaddr(a1),-(sp)
bra.s remmcast
DMCRO EQU 4+(4*4)
delmcastrange:
lea dd_multicastssema(a3),a0
jsr _LVOObtainSemaphore(a6) ; lock access to list
move.l dd_multicasts(a3),a2 ; a2 = first entry in multicast list
bra.s .getmulti
.check:
move.l DMCRO+0+0(sp),d0
cmp.l mcastar_loweraddr(a2),d0
bne.s .next
move.w DMCRO+0+4(sp),d0
cmp.w mcastar_loweraddr+4(a2),d0
bne.s .next
move.l DMCRO+8+0(sp),d0 ; is it our address ?
cmp.l mcastar_upperaddr(a2),d0
bne.s .next
move.w DMCRO+8+4(sp),d0
cmp.w mcastar_upperaddr+4(a2),d0
bne.s .next
subq.l #1,mcastar_count(a2) ; one less count
bne.s .done
bug <"cnet: mcast entry $%08lx removed",10>,a2
move.l a2,a1
REMOVE ; remove entry from list
move.l a2,a1
moveq #mcastar_sizeof,d0
jsr _LVOFreeMem(a6) ; free memory used by entry
move.l a3,a0
bsr update_multicasts ; update multicasts in nic
bra.s .done
.next:
move.l d1,a2 ; get next node in list
.getmulti:
move.l (a2),d1 ; end of list ?
bne.s .check
moveq #S2WERR_BAD_MULTICAST,d0
move.b #S2ERR_BAD_STATE,io_error(a4)
move.l d0,ios2_wireerror(a4)
.done:
lea dd_multicastssema(a3),a0
jmp _LVOReleaseSemaphore(a6) ; release lock on list
;================================================================
; Update Multicasts
;================================================================
;
; calculate multicast hash table and send it to nic
;
; as of 1.2beta4 multicasts can be a address range, also single
; addresses are defined with lower = upper.
;
; update_multicasts(device)
; a0
update_multicasts:
movem.l d2-d4/a2,-(sp)
move.l dd_multicasts(a0),a2
lea mcastaddr(pc),a0
clr.l (a0)+ ; clear all multicast bits
clr.l (a0)+
subq.l #8,sp ; temp for address
.next:
move.l (a2),d4
beq.s .update ; end of list ?
move.l mcastar_loweraddr(a2),(sp)
move.w mcastar_loweraddr+4(a2),4(sp)
.hashall:
moveq #-1,d0 ; initial crc seed
moveq #6,d1 ; 6 bytes in ethernet address
move.l sp,a0 ; data to crc
.nextbyte:
move.b (a0)+,d3 ; get next data byte
moveq #8,d2 ; 8 bits in byte
.nextbit:
lsl.l #1,d0 ; crc << 1
bcc.s .crcnot1
lsr.b #1,d3 ; data >> 1
bcc.s .xor
bra.s .skipnext
.crcnot1:
lsr.b #1,d3 ; data >> 1
bcc.s .skipnext
.xor:
eor.l #$04c11db7,d0 ; crc = crc XOR polynomial
.skipnext:
subq.l #1,d2
bne.s .nextbit
subq.l #1,d1
bne.s .nextbyte
rol.l #6,d0
lea mcastaddr(pc),a0
and.w #%0000000000111111,d0 ; isolate upper 6 bits
move.w d0,d1
and.b #%00000111,d0 ; d0 = bit in byte
lsr.w #3,d1 ; d1 = byte offset
bset d0,0(a0,d1.w) ; set bit for hashed multicast address
move.l mcastar_upperaddr+2(a2),d0
move.w mcastar_upperaddr(a2),d1
cmp.l 2(sp),d0 ; all done with this range ?
bne.b .still
cmp.w (sp),d1
beq.b .donext ; all done with this range ?
.still:
; increment to next address...
addq.l #1,2(sp)
bne.b .hashall ; did we overflow 32bit ?
addq.w #1,(sp) ; 48bit add fix
bra.s .hashall
.donext:
move.l d4,a2
bra.s .next
.update:
addq.l #8,sp
bsr put_multi ; update multicast bits in nic
movem.l (sp)+,d2-d4/a2
rts
ifgt 0 ; this stuff inlined
;==============================================================
; hash multicast address
;==============================================================
; The nic does not compare multicast addresses directly, but
; instead uses a bitfield of 64 bits - each bit corresponds
; to a 6 bit hash code for the multicast address. If the bit
; is set then any multicast address that matches the hash code
; will be accepted.
;
; The hash code is generated by taking the upper 6 bits of the
; 32 bit crc of the multicast address.
;
; hash_multi(address)
; a0
;
hash_multi:
moveq #-1,d0 ; initial crc seed
moveq #6,d1 ; 6 bytes in ethernet address
bsr.s calc_crc ; calculate crc for this multicast address
rol.l #6,d0
lea mcastaddr(pc),a0
and.w #%0000000000111111,d0 ; isolate upper 6 bits
move.w d0,d1
and.b #%00000111,d0 ; d0 = bit in byte
lsr.w #3,d1 ; d1 = byte offset
bset d0,0(a0,d1.w) ; set bit for hashed multicast address
rts
;===========================================================================
; Calculate 32 bit crc
;===========================================================================
;
; - for each bit: if (crcbit=1 XOR databit=1) then crc=(crc XOR polynomial).
; - polynomial is correct when data bits range 0-x, crc bits range 31-0.
; - crc wraps at 32 bits.
;
; crc = calc_crc(data, seed, bytelength)
; d0.l a0 d0.l d1.l
;
calc_crc:
movem.l d2/d3,-(sp)
.nextbyte:
move.b (a0)+,d3 ; get next data byte
moveq #8,d2 ; 8 bits in byte
.nextbit:
lsl.l #1,d0 ; crc << 1
bcc.s .crcnot1
lsr.b #1,d3 ; data >> 1
bcc.s .xor
bra.s .next
.crcnot1:
lsr.b #1,d3 ; data >> 1
bcc.s .next
.xor:
eor.l #$04c11db7,d0 ; crc = crc XOR polynomial
.next:
subq.l #1,d2
bne.s .nextbit
subq.l #1,d1
bne.s .nextbyte
movem.l (sp)+,d2/d3
rts
endc
;==============================================================
; Put Multicast address bitfield into NIC registers
;==============================================================
;
put_multi:
move.l a6,-(sp)
move.l exec_base(pc),a6
lea mcastaddr(pc),a0
MYDISABLE
delay
move.b nic_cr,d0 ; save old command
delay
move.b #DSCM_PG1|DSCM_NODMA|DSCM_STOP,nic_cr ; select page 1
delay
move.b (a0)+,nic_mar0
delay
move.b (a0)+,nic_mar1
delay
move.b (a0)+,nic_mar2
delay
move.b (a0)+,nic_mar3
delay ; put Multicast bits
move.b (a0)+,nic_mar4
delay
move.b (a0)+,nic_mar5
delay
move.b (a0)+,nic_mar6
delay
move.b (a0),nic_mar7
delay
move.b d0,nic_cr ; restore old command
MYENABLE
move.l (sp)+,a6
rts
;=========================================================
; commands not supported
;=========================================================
;
devcmd_nosupport:
bug <"cnet: Unsupported command %d",10>,io_command-2(a1)
moveq #S2WERR_GENERIC_ERROR,d0
move.b #S2ERR_NOT_SUPPORTED,io_error(a1)
move.l d0,ios2_wireerror(a1)
bra TermIO
;==========================================================
; doevent([device,] events)
; a0 d0
;==========================================================
;
; called when an 'important' event occurs
;
DoEvent:
bug <"cnet: doevent $%08lx ...">,d0
movem.l d2-d3/a2/a6,-(sp)
move.l exec_base(pc),a6
move.l d0,d2
move.l me_myself(pc),a0 ; get global pointer to self...
MYDISABLE ; lock eventlist
move.l dd_eventlist(a0),a2 ; get first ioreq
bra.s .start
.loop:
move.l ios2_wireerror(a2),d0
and.l d2,d0 ; ioreq for our events?
beq.s .next
move.l d0,ios2_wireerror(a2) ; set the actual events
move.l a2,a1
REMOVE ; remove ioreq from list
move.b #NT_REPLYMSG,ln_type(a2)
move.l a2,a1
bug <"cnet: returned eventreq $%lx",10>,a1
jsr _LVOReplyMsg(a6) ; send reply to ioreq owner
.next:
move.l d3,a2 ; next ioreq
.start:
move.l (a2),d3 ; last ioreq ?
bne.s .loop
MYENABLE ; unlock eventlist
bug <10,"cnet: doevent done",10>
movem.l (sp)+,d2-d3/a2/a6
rts
;==================================================================
; RemoteRead(buffer, nicbuffer, length)
; a1 d0.w d1.w
;==================================================================
;
; Get a copy of data stored in the network card's onboard RAM.
;
; buffer = Amiga RAM
;
; nicbuffer = 16 bit address in card memory
;
CNOP 0,4
;RemoteRead:
REMOTEREAD MACRO
ifd turboio
addq.w #3,d1 ; bump up count to even value
and.w #-4,d1
delay
swap d1
move.b nic_cr,d1 ; save old command
swap d1
delay
move.b #DSCM_NODMA|DSCM_START,nic_cr ; select bank 0
delay
move.b d1,nic_rbcr0 ; set count.lo
ror.w #8,d1
delay
move.b d1,nic_rbcr1 ; set count.hi
delay
move.b d0,nic_rsar0 ; set address.lo
ror.w #8,d0
delay
move.b d0,nic_rsar1 ; set address.hi
delay
move.b #DSCM_RREAD|DSCM_START,nic_cr ; request Remote Read
ror.w #8,d1
move.w d1,d0
and.w #%0000000000111100,d1
lea nic_data,a0
lsr.w #1,d1
lsr.w #6,d0
neg.w d1
jmp .rr_startread(pc,d1.w)
.rr_dmaread:
move.l (a0),(a1)+
move.l (a0),(a1)+
move.l (a0),(a1)+
move.l (a0),(a1)+
move.l (a0),(a1)+
move.l (a0),(a1)+
move.l (a0),(a1)+
move.l (a0),(a1)+
move.l (a0),(a1)+
move.l (a0),(a1)+
move.l (a0),(a1)+
move.l (a0),(a1)+
move.l (a0),(a1)+
move.l (a0),(a1)+
move.l (a0),(a1)+
move.l (a0),(a1)+
.rr_startread:
subq.w #1,d0
bpl.s .rr_dmaread
move.b #DSIS_RDC,nic_isr ; Remote DMA Complete
swap d1
delay
move.b d1,nic_cr ; restore old command
;rts
else
addq.w #1,d1 ; bump up count to even value
and.w #-2,d1
delay
swap d1
move.b nic_cr,d1 ; save old command
swap d1
delay
move.b #DSCM_NODMA|DSCM_START,nic_cr ; select bank 0
delay
move.b d1,nic_rbcr0 ; set count.lo
ror.w #8,d1
delay
move.b d1,nic_rbcr1 ; set count.hi
delay
move.b d0,nic_rsar0 ; set address.lo
ror.w #8,d0
delay
move.b d0,nic_rsar1 ; set address.hi
delay
move.b #DSCM_RREAD|DSCM_START,nic_cr ; request Remote Read
ror.w #8,d1
move.w d1,d0
and.w #%0000000000011110,d0
lea nic_data,a0
neg.w d0
lsr.w #5,d1
jmp .rr_startread(pc,d0.w)
.rr_dmaread:
move.w (a0),(a1)+
move.w (a0),(a1)+
move.w (a0),(a1)+
move.w (a0),(a1)+
move.w (a0),(a1)+
move.w (a0),(a1)+
move.w (a0),(a1)+
move.w (a0),(a1)+
move.w (a0),(a1)+
move.w (a0),(a1)+
move.w (a0),(a1)+
move.w (a0),(a1)+
move.w (a0),(a1)+
move.w (a0),(a1)+
move.w (a0),(a1)+
move.w (a0),(a1)+
.rr_startread:
subq.w #1,d1
bpl.s .rr_dmaread
move.b #DSIS_RDC,nic_isr ; Remote DMA Complete
swap d1
delay
move.b d1,nic_cr ; restore old command
;rts
endc
ENDM
;=================================================================
; RemoteWrite( buffer, nicbuffer, count )
; a1 d0.w d1.w
;=================================================================
;
; Puts data into the network card's onboard RAM
;
; buffer = Amiga memory
;
; nicbuffer = 16 bit address in card RAM
;
;
CNOP 0,4
;RemoteWrite:
REMOTEWRITE MACRO
ifd turboio
addq.w #3,d1
and.w #-4,d1 ; bump up count to even value
swap d1
delay
move.b nic_cr,d1 ; save old command
swap d1
delay
move.b #DSIS_RDC,nic_isr ; remote DMA complete
delay
move.b #DSCM_NODMA|DSCM_START,nic_cr ; select bank 0
delay
move.b d0,nic_rsar0 ; set address.lo
lsr.w #8,d0
delay
move.b d0,nic_rsar1 ; set address.hi
delay
move.b d1,nic_rbcr0 ; set count.lo
ror.w #8,d1
delay
move.b d1,nic_rbcr1 ; set count.hi
delay
move.b #DSCM_START|DSCM_RWRITE,nic_cr ; request remote write
ror.w #8,d1
; write the etherpacket header & prepare for the copy loop.
lea nic_data,a0
sub.w #ether_data+2,d1
move.l txbuffer(pc),(a0)
move.w d1,d0
move.l txbuffer+4(pc),(a0)
and.w #%0000000000111100,d1
move.l txbuffer+8(pc),(a0)
lsr.w #1,d1
move.w txbuffer+12(pc),(a0)
lsr.w #6,d0
neg.w d1
move.w (a1)+,(a0)
jmp .rw_startwrite(pc,d1.w)
.rw_dmawrite:
move.l (a1)+,(a0)
move.l (a1)+,(a0)
move.l (a1)+,(a0)
move.l (a1)+,(a0)
move.l (a1)+,(a0)
move.l (a1)+,(a0)
move.l (a1)+,(a0)
move.l (a1)+,(a0)
move.l (a1)+,(a0)
move.l (a1)+,(a0)
move.l (a1)+,(a0)
move.l (a1)+,(a0)
move.l (a1)+,(a0)
move.l (a1)+,(a0)
move.l (a1)+,(a0)
move.l (a1)+,(a0)
.rw_startwrite:
subq.w #1,d0
bpl.s .rw_dmawrite
move.w #30000,d0 ; set timeout
.rw_check:
delay
move.b nic_isr,d1 ; wait for remote DMA complete
and.b #DSIS_RDC,d1
dbne d0,.rw_check
; d0.w < 0 send timed out
; d0.w >= 0 send succeeded
delay
move.b #DSIS_RDC,nic_isr ; Remote DMA complete
swap d1
delay
move.b d1,nic_cr ; restore old command
;rts
else
addq.w #1,d1
and.w #-2,d1 ; bump up count to even value
swap d1
delay
move.b nic_cr,d1 ; save old command
swap d1
delay
move.b #DSIS_RDC,nic_isr ; remote DMA complete
delay
move.b #DSCM_NODMA|DSCM_START,nic_cr ; select bank 0
delay
move.b d0,nic_rsar0 ; set address.lo
lsr.w #8,d0
delay
move.b d0,nic_rsar1 ; set address.hi
delay
move.b d1,nic_rbcr0 ; set count.lo
ror.w #8,d1
delay
move.b d1,nic_rbcr1 ; set count.hi
delay
move.b #DSCM_START|DSCM_RWRITE,nic_cr ; request remote write
; write the etherpacket header & prepare for the copy loop.
lea nic_data,a0
ror.w #8,d1
move.w txbuffer(pc),(a0)
sub.w #ether_data,d1
move.w txbuffer+2(pc),(a0)
move.w d1,d0
move.w txbuffer+4(pc),(a0)
move.w txbuffer+6(pc),(a0)
and.w #%0000000000011110,d1
move.w txbuffer+8(pc),(a0)
lsr.w #5,d0
move.w txbuffer+10(pc),(a0)
neg.w d1
move.w txbuffer+12(pc),(a0)
jmp .rw_startwrite(pc,d1.w)
.rw_dmawrite:
move.w (a1)+,(a0)
move.w (a1)+,(a0)
move.w (a1)+,(a0)
move.w (a1)+,(a0)
move.w (a1)+,(a0)
move.w (a1)+,(a0)
move.w (a1)+,(a0)
move.w (a1)+,(a0)
move.w (a1)+,(a0)
move.w (a1)+,(a0)
move.w (a1)+,(a0)
move.w (a1)+,(a0)
move.w (a1)+,(a0)
move.w (a1)+,(a0)
move.w (a1)+,(a0)
move.w (a1)+,(a0)
.rw_startwrite:
subq.w #1,d0
bpl.s .rw_dmawrite
move.w #30000,d0 ; set timeout
.rw_check:
delay
move.b nic_isr,d1 ; wait for remote DMA complete
and.b #DSIS_RDC,d1
dbne d0,.rw_check
; if d0.w<0 timed out
; if d0.w>=0 succeeded
delay
move.b #DSIS_RDC,nic_isr ; Remote DMA complete
swap d1
delay
move.b d1,nic_cr ; restore old command
;rts
endc
ENDM
;=========================================================
; reset_nic()
;=========================================================
;
reset_nic:
delay
move.b nic_rst,d0 ; start reset pulse
delay
move.b d0,nic_rst ; end reset pulse
delay
move.b #DSCM_NODMA|DSCM_STOP,nic_cr ; stop controller
bsr.s delay1500 ; wait 1.5mS
move.b #$ff,nic_isr ; clear all nic ints
rts
;======================
; delay approx 1.5mS
;======================
;
delay1500:
move.l d0,-(sp)
move.w #1500,d0
.loop:
tst.b $bfe001 ; wait 1uS
dbf d0,.loop
move.l (sp)+,d0
rts
;========================================================================
; init_nic(device)
; a1
;========================================================================
;
; Set up the network card for online operation. We also get the hardware
; station address from the nic's ROM.
;
init_nic:
movem.l d2/a5/a6,-(sp)
move.l exec_base(pc),a6
move.l a1,a5 ; a5 = device data
MYDISABLE ; ignore ints while setting up
btst #DDB_NICUP,dd_flags(a5)
bne .ok ; already initialised ?
move.b #DSDC_WTS|DSDC_FT1|DSDC_BMS,dd_dcr(a5) ; Word Xfer, FIFO, Burst
move.b #DSRC_AB|DSRC_AM,dd_rcr(a5) ; accept broadcast & multicast
btst #DDB_PROM,dd_flags2(a5)
beq.s .notprom ; if promiscuous..
or.b #DSRC_SEP|DSRC_PRO|DSRC_AR,dd_rcr(a5) ; ..accept all packets
.notprom:
move.b #INTMASK,dd_imr(a5) ; accept useful interrupts
bsr reset_nic ; reset the controller
delay
move.b nic_cr,d0 ; get command
cmp.b #DSCM_NODMA|DSCM_STOP,d0
bne .error1 ; correct response ?
delay
move.b dd_dcr(a5),nic_dcr ; set data configuration register
delay
move.b #0,nic_rbcr0 ; clear remote byte count
delay
move.b #0,nic_rbcr1 ; ''
delay
move.b #DSRC_MON,nic_rcr ; set rx to monitor mode
delay
move.b #DSTC_LB0,nic_tcr ; set tx to loopback mode 1
delay
move.b #(RBUFEND/256)-1,nic_bnry ; set boundary page
delay
move.b #RBUF/256,nic_pstart ; set start of rx ring buffer
delay
move.b #RBUFEND/256,nic_pstop ; set end of rx ring buffer
delay
move.b #$ff,nic_isr ; clear all interrupts
delay
move.b #0,nic_imr ; no interrupts allowed
delay
move.b nic_rsr,d0
delay
move.b nic_ncr,d0
delay
move.b nic_cntr0,d0 ; read status registers
delay
move.b nic_cntr1,d0
delay
move.b nic_cntr2,d0
delay
move.b #ETHER_ADDR_SIZE*2,nic_rbcr0 ; byte count low = (words)
delay
move.b #0,nic_rbcr1 ; byte count high = 0
delay
move.b #0,nic_rsar0 ; remote start addr low = 0 (ROM)
delay
move.b #0,nic_rsar1 ; remote start addr high = 0 (ROM)
delay
move.b #DSCM_RREAD,nic_cr ; start remote read to get
delay ; station address from ROM
lea dd_romstationaddress(a5),a0
moveq #ETHER_ADDR_SIZE,d0
.getaddr:
move.b nic_data,(a0)+ ; get ROM station address
subq.l #1,d0 ; NOTE: 'move.b' as ROM is 8 bit
bne.s .getaddr
move.w #30000,d1
.waitloop:
delay
move.b nic_isr,d0
and.b #DSIS_RDC,d0 ; wait for remote DMA complete
dbne d1,.waitloop
tst.w d1
bmi .error2 ; error if timed out
delay
move.b #DSIS_RDC,nic_isr ; clear remote DMA complete int
lea dd_romstationaddress(a5),a0
tst.b (a0)
bmi.s .badaddr ; good station address ?
move.l 2(a0),d0
beq.s .badaddr
cmp.l #-1,d0
bne.s .gotstation
.badaddr:
bug <"cnet: bad station address %08lx%04lx, using default",10>,(a0),2(a0)
lea default_address(pc),a0
.gotstation:
bug <"cnet: station address set to %08lx%04lx",10>,(a0),2(a0)
lea dd_stationaddress(a5),a1
move.l (a0)+,(a1)+ ; copy address to device data
move.w (a0)+,(a1)+
lea dd_stationaddress(a5),a0
delay
move.b #DSCM_NODMA|DSCM_PG1|DSCM_STOP,nic_cr ; select bank 1
delay
move.b (a0)+,nic_par0
delay
move.b (a0)+,nic_par1
delay
move.b (a0)+,nic_par2
delay ; set station address
move.b (a0)+,nic_par3
delay
move.b (a0)+,nic_par4
delay
move.b (a0),nic_par5
delay
move.b #RBUF/256,nic_curr ; set current page for rx
move.b #DSCM_NODMA|DSCM_START,d0
delay
move.b d0,nic_cr ; start controller
delay
cmp.b nic_cr,d0
bne .error3 ; command accepted ?
bsr put_multi ; load multicast registers
delay
move.b dd_rcr(a5),nic_rcr ; normal rx mode
delay
move.b #0,nic_tcr ; loopback mode off
delay
move.b #TBUF/256,nic_tpsr ; init tx start page
delay
move.b #$ff,nic_isr ; clear all interrupts
delay
move.b dd_imr(a5),nic_imr ; enable nic interrupts
bset #DDB_NICUP,dd_flags(a5) ; nic is initialised
.ok:
lea dd_devicestats+s2ds_laststart(a5),a0
bsr get_time ; record start time_of_day
bug <"cnet: init_nic OK",10>
moveq #0,d0 ; return OK
.done:
MYENABLE ; allow interrupt processing
movem.l (sp)+,d2/a5/a6
rts
.error1:
bug <"cnet: failed reset, card not compatible?",10>
bra.s .bad
.error2:
bug <"cnet: DMA timeout getting station address!",10>
bra .reset
.error3:
bug <"cnet: failed to start controller, card faulty?",10>
.reset:
bsr reset_nic ; reset nic after malfunction
.bad:
moveq #S2EVENT_ERROR|S2EVENT_HARDWARE,d0
bsr DoEvent
moveq #-1,d0 ; return error
bra .done
;--------------------------------------------------------
; kill_nic(device)
; a1
;--------------------------------------------------------
;
kill_nic:
bug <"cnet: kill_nic",10>
move.l a6,-(sp)
move.l exec_base(pc),a6
MYDISABLE
bclr #DDB_NICUP,dd_flags(a1)
beq.s .done ; already killed ?
bsr reset_nic ; reset controller
delay
move.b #DSRC_MON,nic_rcr ; set rx to monitor mode
delay
move.b #DSTC_LB0,nic_tcr ; set tx to loopback mode
.done:
MYENABLE
move.l (sp)+,a6
rts
;========================================================
; txintcode(device)
; a1
;========================================================
;
; send packets to network card. packets will be put
; into the card's onboard 16 bit ram, and then
; transmitted to the wire.
;
; scratch: d0-d1, a0-a1, and a5 (softint must preserve a6!)
;
txintcode:
movem.l d2-d4/a2-a3/a6,-(sp)
move.l exec_base(pc),a6
move.l a1,a5 ; a5 = device
.next:
btst #DDB_TX,dd_flags(a5) ; quit if tx in progress (status int
bne.s .done ; will restart us when tx complete)
lea dd_writelist(a5),a0
MYREMHEAD ; remove top ioreq
bne.s .gotreq ; any ioreqs to process?
.done:
movem.l (sp)+,d2-d4/a2-a3/a6
moveq #0,d0
rts
.gotreq:
move.l d0,a3 ; a3 = ioreq
lea txbuffer(pc),a1 ; a1 = our internal packet buffer
move.l ios2_buffermanagement(a3),a2
move.l ios2_datalength(a3),d4 ; default: raw packet's full length
move.l ios2_packettype(a3),d3 ; d3 = packettype (must be in d3 in non-raw too!!!)
tst.b io_flags(a3) ; (test SANA2IOB_RAW) raw packets?
bmi.s .send
; ok. it's not raw packet so we need to build etherheader for it.
; first destination and source addresses then packet type. easy!
lea ios2_dstaddr(a3),a0 ; dstaddress
move.l (a0)+,(a1)+
move.w (a0)+,(a1)+
lea dd_stationaddress(a5),a0 ; from address
move.l (a0)+,(a1)+
move.w (a0)+,(a1)+
move.w d3,(a1)+ ; insert packettype into packet
add.w #ether_data,d4 ; d4 = length of header + data
.send:
; Do we have the tag for DMA?
lea bufman_dmacopyfrombuf32(a2),a2
move.l a1,d2 ; d2 = where to copyfrom
move.l (a2)+,d0
beq.s .nodma
; Ask for the DMA address
move.l d0,a1
move.l ios2_data(a3),a0 ; a0=abstract magic cookie ios2_Data
jsr (a1)
tst.l d0 ; dma possible?
move.l d0,a1
; If dma is possible we now have the direct application buffer
; in a1.. and we can use that directly with RemoteWrite! cool.
ifd verbose
tst.l d0
beq.s .v1_nodma
bug <"cnet: using DMA write from $%08lx!",10>,a1
tst.l d0
.v1_nodma:
endc
bne.s .copyok ; do it with DMA?
.nodma:
; Ohwell, the caller doesn't support DMA transfer, so lets fall
; back to regular copyfrom.
move.l d2,a0 ; a0=to (contiguous)
move.l ios2_data(a3),a1 ; a1=from (abstract)
move.l (a2),a2 ; get bufman_copyfrombuf
move.l ios2_datalength(a3),d0 ; d0=n
jsr (a2)
tst.l d0
beq .copyfromfail ; oh fuck.. copyfrombuf failed!
; we can return the ioreq now!
move.l a3,a1
sub.l a3,a3
bsr TermIO ; finish IOrequest
lea txbuffer+ether_data(pc),a1 ; non-DMA so use txbuffer for copy!!
.copyok:
moveq #ETHER_MIN_LEN,d0
cmp.l d0,d4
bge.s .min ; d4 adjusted to legal packet size
move.l d0,d4
.min:
ifd verbose
move.l a1,-(sp)
moveq #0,d1
move.w txbuffer+ether_type(pc),d1
bug <"cnet: wrpkt %08lx%04lx >> %08lx%04lx ">,txbuffer+6(pc),txbuffer+8(pc),txbuffer(pc),txbuffer+2(pc)
cmp.w #1500,d1
bhs.s .type
bug <"(IEEE802.3)len %ld, ">,d1
bra.s .bytes
.type:
bug <"type %ld, ">,d1
.bytes:
bug <"%ld bytes",10>,d4
moveq #-ether_data,d0 ; show only the data
add.l d4,d0
bsr showpkt
move.l (sp)+,a1
endc
; copy the transfer buffer to cards memory
move.w #TBUF,d0
move.w d4,d1
; a1 = txbuffer (or DMA buffer)
;bsr RemoteWrite ; put packet into nic tx buffer
REMOTEWRITE
tst.w d0
bmi.s .xmiterr
; now really start the transfer:
MYDISABLE ; disable interrupts during tx setup
bset #DDB_TX,dd_flags(a5) ; set our "buffer full" flag
delay
move.b d4,nic_tbcr0 ; set tx byte count lo
ror.w #8,d4
delay
move.b d4,nic_tbcr1 ; set tx byte count hi
ror.w #8,d4
delay
move.b #DSCM_NODMA|DSCM_TRANS|DSCM_START,nic_cr ; start tx
MYENABLE ; enable interrupts
; update statistics:
move.l dd_tracklist(a5),a0
.getstats:
move.l (a0),d2 ; tracking packettypes ?
beq.s .statsdone
cmp.l ss2_ptype(a0),d3 ; stats entry for our type ?
beq.s .gotstats
move.l d2,a0 ; try next stats entry
bra.s .getstats
.gotstats:
add.l d4,ss2_stats+s2pts_txbytes(a0)
addq.l #1,ss2_stats+s2pts_txpackets(a0)
.statsdone:
.termio:
move.l a3,d0 ; have we replied it already?
beq .next ; we have! process next ioreq
move.l a3,a1
bsr TermIO ; finish IOrequest
bra .next ; process next ioreq
.copyfromfail:
; note: doesn't get called if a3=0
moveq #S2EVENT_TX|S2EVENT_BUFF,d0
bsr DoEvent
clr.l ios2_datalength(a3)
moveq #S2WERR_BUFF_ERROR,d0
move.b #S2ERR_NO_RESOURCES,io_error(a3)
move.l d0,ios2_wireerror(a3)
bra.s .termio
.xmiterr:
moveq #S2EVENT_ERROR|S2EVENT_TX,d0
bsr DoEvent
bra.s .termio
;============================================================
; rxintcode(device)
; a1
;============================================================
;
; service rx interrupts
;
; scratch: d0-d1, a0-a1, and a5 (softint must preserve a6!)
;
rxintcode:
movem.l d6/d7/a6,-(sp)
move.l exec_base(pc),a6
move.l a1,a5 ; a5 = device
.nextpage:
MYDISABLE
delay
moveq #0,d7
move.b #DSCM_NODMA|DSCM_PG1|DSCM_START,nic_cr ; select bank 1
move.b nic_curr,d7 ; d7 = current page
delay
move.b #DSCM_NODMA|DSCM_START,nic_cr ; select bank 0
MYENABLE
moveq #0,d6
delay
move.b nic_bnry,d6
addq.w #1,d6 ; d6 = next page (boundary+1)
cmp.w #RBUFEND/256,d6
blo.s .nowrap ; end of buffer mem ?
moveq #RBUF/256,d6 ; wrap around to start
.nowrap:
cmp.w d6,d7 ; current page = next page ?
beq .done ; if so then nothing to get
ifgt 0
move.w d6,d0
lea rx_header(pc),a1 ; a1 = buffer
lsl.w #8,d0 ; d0 = 16 bit page address
moveq #prhdr_sizeof+ether_data,d1
bsr RemoteRead ; get packet header
else
; inlined RemoteRead:
lea nic_data,a0
lea rx_header(pc),a1 ; a1 = buffer
delay
move.b nic_cr,d1 ; save old command
delay
move.b #DSCM_NODMA|DSCM_START,nic_cr ; select bank 0
delay
move.b #prhdr_sizeof+ether_data,nic_rbcr0 ; set count.lo
delay
move.b #0,nic_rbcr1 ; set count.hi
delay
move.b #0,nic_rsar0 ; set address.lo
delay
move.b d6,nic_rsar1 ; set address.hi (d6=16 bit page address hi)
delay
move.b #DSCM_RREAD|DSCM_START,nic_cr ; request Remote Read
; transfer prhdr_sizeof+ether_data = 4+14 = 18 = 2*9
ifd turboio
move.l (a0),(a1)+ ; 4*4 = 16
move.l (a0),(a1)+
move.l (a0),(a1)+
move.l (a0),(a1)+
else
move.w (a0),(a1)+ ; 4*4 = 16
move.w (a0),(a1)+
move.w (a0),(a1)+
move.w (a0),(a1)+
move.w (a0),(a1)+
move.w (a0),(a1)+
move.w (a0),(a1)+
move.w (a0),(a1)+
endc
move.w (a0),(a1)+ ; +2
move.b #DSIS_RDC,nic_isr ; Remote DMA Complete
delay
move.b d1,nic_cr ; restore old command
endc
move.b rx_header+prhdr_status(pc),d0
and.b #DSRS_RPC,d0 ; complete packet received ?
bne.s .goodpacket
bug <"cnet: incomplete packet received",10>
addq.l #1,dd_devicestats+s2ds_baddata(a5) ; count bad packets received
bra.s .next
.goodpacket:
addq.l #1,dd_devicestats+s2ds_packetsreceived(a5) ; count packets received
move.l a5,a0
move.w d6,d0
;lea rx_header(pc),a1
bsr.s readpacket ; feed packet into waiting ioreqs
.next:
moveq #0,d0
move.b rx_header+prhdr_nxtpg(pc),d0 ; get next page number
move.w d0,d7
subq.w #1,d0 ; nxtpage-1 = new boundary
cmp.w #RBUF/256,d0
bge.s .boundary ; wrap if before 1st page
moveq #(RBUFEND/256)-1,d0
.boundary:
delay
move.b d0,nic_bnry ; set new boundary
bra .nextpage ; back for more
.done:
delay
move.b #DSCM_NODMA|DSCM_START,nic_cr ; select bank 0
MYDISABLE
delay
move.b nic_rsr,d0 ; read rx status
delay
move.b nic_cntr0,d0
delay
move.b nic_cntr1,d0 ; read counters
delay
move.b nic_cntr2,d0
or.b #DSIM_OVWE|DSIM_RXEE|DSIM_PRXE,dd_imr(a5)
move.b dd_imr(a5),nic_imr ; allow rx interrupts
MYENABLE
movem.l (sp)+,d6/d7/a6
moveq #0,d0
rts
;==============================================================
; readpacket( device, [pkthdr], page )
; a0 [a1] d0.w
;==============================================================
;
; get packet from network card and feed it to all different
; CMD_READ queues. Also call packet filter before doing the copy.
;
; Note that this is a major improvement to previous implementation,
; that only kept one single list of CMD_READs. This finally fixes
; sanamon for example.
;
; Inputs:
;
; pkthdr = packet header info extracted from nic
;
; page = 256 byte page in nic RAM that holds packet
;
;
readpacket:
movem.l d2-d7/a2-a6,-(sp)
moveq #0,d6
move.w d0,d7 ; d7 = page
move.l a0,a5 ; a5 = device
move.b rx_header+prhdr_sz1(pc),d6
moveq #0,d3
lsl.w #8,d6
move.w rx_header+prhdr_sizeof+ether_type(pc),d3
move.b rx_header+prhdr_sz0(pc),d6
lsl.w #8,d7 ; address=page*256
sub.w #prhdr_sizeof+ether_data,d6 ; d6 = length of read
add.w #prhdr_sizeof+ether_data,d7 ; skip pageheader and etherheader
; dropflag is set to true if at least one protocol stack managed
; to get the packet. If this still is zero after the following loop
; then I try to feed to for pending S2_READORPHAN request, if any.
moveq #0,d4 ; dropflag
move.l dd_bufmanlist(a5),a3 ; a3 = first bufman
bra.s .start
; scan each CMD_READ callers bufmanlist until we find the ioreq
; that want this type of packet or till end of list.
.nextreq:
move.l (a3),d0
beq.s .nextbufman ; end of this CMD_READ list ?
cmp.l ios2_packettype(a3),d3
beq.s .iwantyou ; does it want our packet ?
cmp.w #1500,d3
bhi.s .nextnode ; accept 802.3 packets
cmp.l #1500,ios2_packettype(a3)
bls.s .iwantyou
.nextnode:
move.l d0,a3
bra.s .nextreq
.iwantyou:
; a3 = ioreq
moveq #1,d2 ; use packetfilter
bsr .gotreq
; note that we only offer it once per caller!
.nextbufman:
move.l d5,a3 ; a3 = next bufman node in list
.start:
move.l (a3),d5
move.l bufman_rxqueue(a3),a3 ; get pending CMD_READ's list
bne.s .nextreq ; end of bufman list ?
; Now we've tried to give the packet to every CMD_READ caller,
; and d4 contains the number of iorequests that were succesfully
; returned. If d4 is 0 at this point no-one wanted this packet.
tst.l d4
beq.s .gotdropped ; did oneone want it?
; Okay, at least one CMD_READ caller got the packet, so we're happy
; now and can quit.
.done:
movem.l (sp)+,d2-d7/a2-a6
rts
.gotdropped:
; so there were no outstanding CMD_READs or the packet wasn't
; accepted by any of them. Okay, check if we have any pending
; S2_READORPHAN ioreq in list and if we have return this packet
; with it. Note that packet filter must not be used for this
; time!
addq.l #1,dd_devicestats+s2ds_unknowntypesreceived(a5)
move.l dd_orphanlist(a5),a3 ; get first S2_READORPHAN available
tst.l (a3)
beq.s .dotrack ; got an orphan ioreq ?
; d4 = whatever, not important here
; a3 = ioreq
moveq #0,d2 ; indicate S2_READORPHAN call
bsr.s .gotreq
.dotrack:
; Update dropped packet statistics, if requested.
move.l dd_tracklist(a5),a0
.getstat:
move.l (a0),d0 ; tracking packettypes ?
beq.s .donetrk
cmp.l ss2_ptype(a0),d3 ; get tracking entry for this type
beq.s .dropped
move.l d0,a0 ; next tracking entry
bra.s .getstat
.dropped:
addq.l #1,ss2_stats+s2pts_packetsdropped(a0) ; another packet dropped
.donetrk:
bug <"cnet: packet type %ld dropped",10>,d3
moveq #S2EVENT_ERROR|S2EVENT_RX,d0
bsr DoEvent
bra .done
.gotreq:
; Here we have a ioreq in a3 that has requested packets of this type.
; 1st we extract the packet from the card unless we have already done
; so. d2 = 0 if this ioreq is S2_READORPHAN call (packetfilter must
; not be used). if d2 = 1 then this is a regular CMD_READ and
; packetfilter must be called.
tst.w d7
beq.s .gotalready ; have we already read it ?
lea rxbuffer+ether_data(pc),a1
move.w d7,d0 ; (we only get the user stuff here)
move.w d6,d1
;bsr RemoteRead ; get packet user data from nic
REMOTEREAD
ifd verbose
bug <"cnet: rdpkt %08lx%04lx < %08lx%04lx, ">,rxbuffer+ether_dest(pc),rxbuffer+ether_dest+2(pc),rxbuffer+ether_src(pc),rxbuffer+ether_src+2(pc)
cmp.w #1500,d3
bhi.s .type
bug <"(IEEE802.3)len %ld, ">,d3
bra.s .bytes
.type:
bug <"type %ld, ">,d3
.bytes:
moveq #ether_data,d0
add.l d6,d0
bug <"%ld bytes",10>,d0
lea rxbuffer+ether_data(pc),a1
move.l d6,d0
bsr showpkt
endc
; Update the packet statistics if required.
move.l dd_tracklist(a5),a0
.getstats:
move.l (a0),d0 ; tracking packettypes ?
beq.s .received
cmp.l ss2_ptype(a0),d3 ; find stats entry for our type
beq.s .gotstats
move.l d0,a0
bra.s .getstats
.gotstats:
add.l d6,ss2_stats+s2pts_rxbytes(a0) ; update stats
addq.l #1,ss2_stats+s2pts_rxpackets(a0)
.received:
moveq #0,d7 ; don't try to read it from hw anymore
.gotalready
; next figure out if this ioreq asked the raw or non-raw data,
; and skip ether_data bytes from the buffer start if it asked
; raw.
move.l d6,ios2_datalength(a3) ; user data size
lea rxbuffer+ether_data(pc),a6 ; a6=user data
tst.b io_flags(a3) ; (test SANA2IOB_RAW)
bpl.s .notraw ; is etherheader wanted ?
add.w #ether_data+4,ios2_datalength+2(a3) ; raw data size
lea rxbuffer(pc),a6 ; a6=raw data
.notraw:
; now build up the ios2 structure enough so we can call the packet
; filter.
lea ios2_dstaddr(a3),a0
lea rxbuffer+ether_dest(pc),a1 ; or: rx_header+prhdr_sizeof+ether_dest
move.l (a1)+,(a0)+ ; extract the dst address
move.w (a1)+,(a0)+
lea ios2_packettype(a3),a0
move.l d3,(a0)+ ; packet type
move.l (a1)+,(a0)+ ; extract the src address
move.w (a1)+,(a0)+
; call the packet filter, if available. real men don't use filters. :-)
; the truth is out there
tst.l d2
move.l ios2_buffermanagement(a3),a0
beq.s .marlboro ; S2_READORPHAN must not use filter!
move.l bufman_packetfilter(a0),d0
beq.s .marlboro ; did the caller provide packet filter ?
move.l d0,a0 ; a0=hook
move.l a6,a1 ; a1=data
move.l 8(a0),a4 ; h_entry - get hook assembler entry point
move.l a3,a2 ; a2=ios2
jsr (a4)
tst.l d0
beq .ignore
.marlboro: ;-!
; ok. the packet didn't get filtered, set the BCAST and MCAST
; flags according to dstaddr.
btst #0,ios2_dstaddr(a3) ; address = Multicast ?
beq.s .nmcast
cmp.l #$ffffffff,ios2_dstaddr(a3)
bne.s .nbcast ; address = Broadcast ?
cmp.w #$ffff,ios2_dstaddr+4(a3)
bne.s .nbcast
bset #SANA2IOB_BCAST,io_flags(a3) ; set BROADCAST flag in ioreq
bra.s .nmcast
.nbcast:
bset #SANA2IOB_MCAST,io_flags(a3) ; set MULTICAST flag in ioreq
.nmcast:
; finally copy the packet data!
move.l ios2_data(a3),a0
move.l ios2_buffermanagement(a3),a2
move.l a6,a1
move.l bufman_copytobuf(a2),a2
move.l ios2_datalength(a3),d0
jsr (a2) ; call copytobuf
tst.l d0
beq.s .copytobuferr
addq.l #1,d4 ; mark that it wasn't dropped!
ifd verbose
bug <"cnet: copytobuffed packet ior %08lx %08lx%04lx < %08lx%04lx, type %ld, %ld bytes, ">,a3,ios2_dstaddr(a3),ios2_dstaddr+2(a3),ios2_srcaddr(a3),ios2_srcaddr+2(a3),ios2_packettype(a3),ios2_datalength(a3)
tst.b io_flags(a3)
bpl.s .v1
bug <"RAW ">
.v1:
btst #SANA2IOB_BCAST,io_flags(a3)
beq.s .v2
bug <"BCAST ">
.v2:
btst #SANA2IOB_MCAST,io_flags(a3)
beq.s .v3
bug <"MCAST ">
.v3:
bug <10>
endc
.termit:
move.l a3,a1
REMOVE ; pull it off the list
move.l a3,a1
bra TermIO ; IO finished
.ignore:
bug <"cnet: packet type %ld for %08lx ior filtered",10>,d3,a3
; the packet got rejected by packet filter!
rts
.copytobuferr:
; oh fuck.. copytobuf failed!
bug <10,"cnet: copytobuf failed!",10>
moveq #S2EVENT_RX|S2EVENT_BUFF,d0
bsr DoEvent
clr.l ios2_datalength(a3)
moveq #S2WERR_BUFF_ERROR,d0
move.b #S2ERR_NO_RESOURCES,io_error(a3)
move.l d0,ios2_wireerror(a3)
bra.s .termit
;======================================================================
; init_card(device)
; a1
;======================================================================
;
; Initialise PCMCIA card
;
init_card:
bug <"cnet: init_card",10>
movem.l d3-d6/a3/a6,-(sp)
move.l a1,a3 ; a3 = device
btst #DDB_OWNED,dd_flags(a3) ; do we own the card already?
bne .owned
move.l dd_cardres(a3),d0
bne.s .gotres
move.l exec_base(pc),a6
lea cardname(pc),a1
jsr _LVOOpenResource(a6) ; open credit card resource
move.l d0,dd_cardres(a3)
beq .error
.gotres:
lea dd_cardhandle(a3),a1
lea dd_cardremoved(a3),a0 ; init interrupt for card removed
move.l a3,is_data(a0)
move.l #card_removed_code,is_code(a0)
move.l a0,cah_CardRemoved(a1)
lea dd_cardinserted(a3),a0 ; init interrupt for card inserted
move.l a3,is_data(a0)
move.l #card_inserted_code,is_code(a0)
move.l a0,cah_CardInserted(a1)
lea dd_cardstatus(a3),a0 ; init interrupt for status change
move.l a3,is_data(a0)
move.l dd_cardres(a3),a6
cmp.w #39,LIB_VERSION(a6) ; got CARDB_POSTSTATUS (v39+) ?
blo.s .oldie
move.l #status_int_code_v39,is_code(a0)
move.b #CARDF_IFAVAILABLE|CARDF_POSTSTATUS,cah_cardflags(a1)
bra.s .was_goldie
.oldie:
move.l #status_int_code_v37,is_code(a0)
move.b #CARDF_IFAVAILABLE,cah_cardflags(a1)
.was_goldie:
move.l a0,cah_CardStatus(a1)
lea devicename(pc),a0
move.l a0,ln_name(a1)
move.b #20,ln_pri(a1) ; high priority for I/O card
jsr _LVOOwnCard(a6) ; own card (sets up interrupt vectors)
tst.l d0
bne .error
or.b #DDF_CARDIN|DDF_OWNED,dd_flags(a3) ; card is inserted & owned by us
.owned:
lea dd_cardhandle(a3),a1
lea tuple(pc),a0
moveq #CISTPL_FUNC_ID,d1
moveq #40,d0
move.l dd_cardres(a3),a6
jsr _LVOCopyTuple(a6) ; read function tuple
tst.l d0
beq .error
lea tuple(pc),a0
move.b 2(a0),d0
cmp.b #CISTPL_FUNCID_NETWORK,d0 ; must be a network card!
bne .error
lea dd_cardhandle(a3),a1
lea tuple(pc),a0
moveq #CISTPL_CONF_MAP,d1
moveq #40,d0
move.l dd_cardres(a3),a6
jsr _LVOCopyTuple(a6) ; read config map tuple
tst.l d0
beq .error
lea tuple(pc),a0
move.b 2(a0),d0
and.w #$03,d0 ; (number of address bytes)-1
moveq #0,d5
.getaddr:
lsl.l #8,d5
move.b 4(a0,d0.w),d5 ; extract config register address
subq.w #1,d0
bpl.s .getaddr
and.l #$0001FFFF,d5 ; limit to attribute memory range
lea dd_cardhandle(a3),a1
moveq #CISTPL_CONFIG,d1
moveq #40,d0
jsr _LVOCopyTuple(a6) ; read 1st config tuple
tst.l d0
beq.s .error
lea dd_cardhandle(a3),a1
move.l #CARDF_DISABLE_WP|CARDF_ENABLE_DIGAUDIO,d1
jsr _LVOCardMiscControl(a6) ; enable card I/O functions
lea tuple(pc),a0
move.b 2(a0),d0 ; extract configuration ID value
.setconfig:
and.b #$3f,d0
lea AttrMem,a0
add.l d5,a0
move.b d0,(a0) ; put ID into card config register
.ok:
bug <"cnet: init_card: OK",10>
moveq #0,d0 ; card is active, return OK
.done:
movem.l (sp)+,d3-d6/a3/a6
rts
.error:
bug <"cnet: init_card: failed!",10>
moveq #S2EVENT_ERROR|S2EVENT_HARDWARE,d0
bsr DoEvent
moveq #-1,d0 ; card not available, return error
bra.s .done
;=================================================================
; initialise device data structures
;=================================================================
;
; init_device(device)
; a1
;
init_device:
movem.l a3/a6,-(sp)
move.l a1,a3
bset #DDB_DEVINIT,dd_flags(a3) ; already initialised ?
bne .done
move.l exec_base(pc),a6
lea dd_orphanlist(a3),a0 ; New MinList for orphan queue
NEWLIST a0
lea dd_writelist(a3),a0 ; New MinList for write queue
NEWLIST a0
lea dd_eventlist(a3),a0 ; New MinList for event queue
NEWLIST a0
lea dd_bufmanlist(a3),a0 ; New MinList for bufman vectors
NEWLIST a0
lea dd_tracklist(a3),a0 ; New MinList for tracking
NEWLIST a0
lea dd_multicasts(a3),a0 ; New MinList for multicast filters
NEWLIST a0
lea dd_multicastssema(a3),a0
jsr _LVOInitSemaphore(a6)
lea dd_rxint+ln_type(a3),a1
lea rxintname(pc),a0
move.w #(NT_INTERRUPT<<8)|16,(a1)+ ; priority 16
move.l a0,(a1)+ ; set up rx swi
lea rxintcode(pc),a0
move.l a3,(a1)+
move.l a0,(a1)+
lea dd_txint+ln_type(a3),a1
lea txintname(pc),a0
move.w #(NT_INTERRUPT<<8)|0,(a1)+ ; priority 0
move.l a0,(a1)+ ; set up tx swi
lea txintcode(pc),a0
move.l a3,(a1)+
move.l a0,(a1)+
.done:
movem.l (sp)+,a3/a6
rts
;============================================================
; PCMCIA status change interrupt
;============================================================
;
; Occurs whenever a PCMCIA status line changes
;
; eg. when the network card activates it's interrupt line
;
;
; entry: d0 = status change(s)
; a1 = device
;
; exit: d0 must be preserved!
;
STATINT MACRO
movem.l d2-d6/a2-a4,-(sp)
move.l a1,a4 ; a4 = device
btst #DDB_NICUP,dd_flags(a4) ; is nic working ?
beq .done
move.l d0,d6 ; d6 = status changes
move.l exec_base(pc),a6
move.b nic_cr,d5 ; save old command
delay
move.b #0,nic_imr ; prevent nic interrupts
bra .checkint
; interrupt service loop (d3 = interrupt status)
.intloop:
btst #DSIB_ROVRN,d3 ; Overwrite warning enable ?
beq .no_overflow
; receiver ring buffer overflowed (eek!)
addq.l #1,dd_overflows(a4)
delay
move.b #0,nic_rbcr0
delay
move.b #0,nic_rbcr1 ; reset remote byte count
delay
move.b #DSTC_LB0,nic_tcr
delay ; monitor mode
move.b #DSRC_MON,nic_rcr
delay
move.b #DSCM_NODMA|DSCM_START,nic_cr ; try to restart controller
delay
move.b #DSRC_AB,nic_rcr
delay ; normal rx mode
move.b #0,nic_tcr
.no_overflow:
btst #DSIB_RXE,d3 ; Receive error enable ?
beq.s .norxerr
; bug <"cnet: rx error",10>
addq.l #1,dd_devicestats+s2ds_baddata(a4) ; another bad rx packet ?
delay
move.b nic_rsr,d0 ; read rx status
delay
move.b nic_cntr0,d0
delay
move.b nic_cntr1,d0 ; read counters
delay
move.b nic_cntr2,d0
bra.s .rx
.norxerr:
btst #DSIB_RX,d3 ; Packet received enable ?
beq.s .no_rx
; new packet(s) arrived in receive ring buffer
.rx:
and.b #~(DSIM_OVWE|DSIM_RXEE|DSIM_PRXE),dd_imr(a4) ; ignore rx ints
lea dd_rxint(a4),a1
jsr _LVOCause(a6) ; to copy packet(s) into waiting ioreq(s)
.no_rx:
btst #DSIB_TXE,d3 ; Transmit error enable ?
bne.s .tx
btst #DSIB_TX,d3 ; Packet transmitted enable ?
beq .no_tx
.tx:
; a packet has just been transmitted
moveq #0,d0
delay
move.b nic_ncr,d0 ; read collision count
bclr #DDB_TX,dd_flags(a4) ; buffer now free
add.l d0,dd_retries(a4) ; increment retry count
addq.l #1,dd_devicestats+s2ds_packetssent(a4) ; count packets sent
lea dd_txint(a4),a1
jsr _LVOCause(a6) ; to transmit next packet
.no_tx:
btst #DSIB_CTRS,d3 ; counter overflow ?
beq.s .nocounter
; counter overflow
delay
move.b nic_cntr0,d0
delay
move.b nic_cntr1,d0 ; read counters
delay
move.b nic_cntr2,d0
.nocounter:
.checkint:
delay
move.b nic_isr,d3 ; d3 = nic interrupt status
delay
move.b d3,nic_isr ; clear current interrupt bit(s)
and.b dd_imr(a4),d3
bne .intloop ; any valid interrupts ?
delay
move.b d5,nic_cr ; restore old command
ENDM
CNOP 0,4
status_int_code_v37:
STATINT
eor.b #$2c,d6
or.b #$c0,d6
move.b d6,$da9000 ; clear PCMCIA status change bits
delay
move.b dd_imr(a4),nic_imr ; enable nic interrupts
moveq #0,d0 ; don't clear status bits coz we did
.done:
movem.l (sp)+,d2-d6/a2-a4
rts
CNOP 0,4
status_int_code_v39:
STATINT
delay
move.b dd_imr(a4),nic_imr ; enable nic interrupts
move.l d6,d0 ; return original d0
.done:
movem.l (sp)+,d2-d6/a2-a4
rts
;============================================================
; PCMCIA Card Inserted interrupt
;============================================================
;
; Occurs whenever a PCMCIA card is plugged in
;
; NOTE: card.resource has given us ownership of the card
;
; entry: a1 = device
;
; exit: d0,d1,a0,a1,a5,a6 = scratch
;
card_inserted_code:
bug <"cnet: PCMCIA card inserted",10>
move.l a1,a5
tst.w lib_opencnt(a5) ; is someone interested about cards ?
beq.s .done
or.b #DDF_CARDIN|DDF_OWNED,dd_flags(a5) ; card is inserted & we own the card again
bsr init_card
tst.l d0 ; attempt to init pcmcia card
bne.s .releasecard
move.l a5,a1
bsr init_nic ; attempt to start controller
tst.l d0
beq.s .good
.releasecard:
lea dd_cardhandle(a5),a1
move.l dd_cardres(a5),a6
moveq #0,d0
jsr _LVOReleaseCard(a6) ; release foreign or bad card
bclr #DDB_OWNED,dd_flags(a5)
bra.s .done
.good:
btst #DDB_OFFLINE,dd_flags(a5) ; has device been put offline ?
bne.s .done
bset #DDB_ONLINE,dd_flags(a5) ; device is now online
moveq #S2EVENT_ONLINE,d0
bra DoEvent ; return ONLINE event
.done:
rts
;============================================================
; PCMCIA Card Removed interrupt
;============================================================
;
; Occurs whenever a PCMCIA card is unplugged
;
; entry: a1 = device
;
; exit: d0,d1,a0,a1,a5,a6 = scratch
;
card_removed_code:
bug <"cnet: PCMCIA card removed",10>
move.l a1,a5 ; a5 = device
;and.b #~(DDF_OWNED|DDF_CARDIN|DDF_ONLINE|DDF_NICUP|DDF_CONFIGURED),dd_flags(a5)
and.b #~(DDF_OWNED|DDF_CARDIN|DDF_ONLINE|DDF_NICUP),dd_flags(a5)
lea dd_cardhandle(a5),a1
move.l dd_cardres(a5),a6
moveq #0,d0
jsr _LVOReleaseCard(a6) ; release card
moveq #S2EVENT_OFFLINE,d0
bra DoEvent ; return OFFLINE event
; debugging stuff...
ifd verbose
showpkt:
movem.l a0-a1/d0-d2,-(sp)
bug <10>
moveq #0,d1
.rows:
moveq #15,d2
lea .string(pc),a0
.bytes:
move.b (a1)+,d1
cmp.b #' ',d1
blo.s .dot
cmp.b #'z',d1
bhs.s .dot
move.b d1,(a0)+
bra.s .ends
.dot:
move.b #'.',(a0)+
.ends:
move.b #0,(a0)
bug <"%02lx ">,d1
subq.w #1,d0
beq.s .end
dbf d2,.bytes
bra.s .shows
.endspc:
bug <" ">
.end:
dbf d2,.endspc
.shows:
bug <" %s",10>,#.string
tst.w d0
bne.s .rows
bug <10,10>
movem.l (sp)+,a0-a1/d0-d2
rts
.string:
ds.b 16
dc.b 0
even
endc
rxintname:
dc.b "cnet rx softint",0
txintname:
dc.b "cnet tx softint",0
cardname:
dc.b "card.resource",0
timerdevname:
dc.b "timer.device",0
utilityName:
dc.b "utility.library",0
multiname:
dc.b "bad multicasts",0
retryname:
dc.b "retries",0
DeviceName:
dc.b "cnet.device",0
dc.b "$VER: "
IDString:
dc.b "cnet.device "
VERSTR
ifeq __CPU-68000
dc.b " 68000+"
else
ifge __CPU-68020
dc.b " 68020+"
endc
endc
ifd turboio
dc.b "/turboio"
endc
ifd debug
dc.b "/debug"
endc
dc.b " by Harry ",34,"Piru",34," Sintonen",10,0
; devicequery block
CNOP 0,2
size_supplied:
dc.l S2DQ_SIZE ; bytes supplied (size of this block)
dc.l 0 ; this is type 0
dc.l 0 ; this document is level 0
dc.w ETHER_ADDR_SIZE*8 ; address size in bits
dc.l ETHERPKT_SIZE ; maximum packet data size
dc.l 10000000 ; line rate (10 Megabits/sec)
dc.l S2WIRETYPE_ETHERNET ; what the wire is
; default station address to use if the card won't give it to us.
CNOP 0,2
default_address:
dc.b $00,$00,$12,$34,$56,$78 ; replace this with your card's address!
;--------------------------------------------------------
; Global data
;--------------------------------------------------------
CNOP 0,4
exec_base: dc.l 0 ; local copy of execbase
utility_base: dc.l 0 ; for walking taglist
me_myself: dc.l 0 ; pointer to this device
timerdevice: dc.l 0 ; timer device base
mcastaddr: ds.b 8 ; multicast address filter bitfield
; ---- Timer I/O Request ----
CNOP 0,2
timereq:
dc.l 0 ; ln_head } }
dc.l 0 ; ln_pred } }
dc.b 0 ; ln_type } mp_node }
dc.b 0 ; ln_pri } } io_message
dc.l 0 ; ln_name } }
dc.l 0 ; mn_replyport }
dc.w 0 ; mn_length }
dc.l 0 ; io_device
dc.l 0 ; io_unit
dc.w 0 ; io_command
dc.b 0 ; io_flags
dc.b 0 ; io_error
dc.l 0 ; tv_secs
dc.l 0 ; tv_micros
tuple: ds.b 48 ; PCMCIA tuple buffer
; linked with phxlnk so no need for separate bss hunk!
; section buffers,bss
CNOP 0,8
rx_header:
ds.b prhdr_sizeof
rxbuffer:
ds.b PKTBUF_SIZE-prhdr_sizeof ; received packet buffer
CNOP 0,8
txbuffer:
ds.b PKTBUF_SIZE ; transmit packet buffer
CNOP 0,2
Endcode: